1. 程式人生 > >從客戶端到後臺,一文通吃

從客戶端到後臺,一文通吃

前記

最近一段時間,因為公司需求,需要轉向Java Web方向發展,Android得放下一段時間(不過還是會利用空餘時間堅持寫文章~)。

推送功能是app很常用的一個功能,目前能夠實現推送的第三方平臺也有不少,比如友盟極光信鴿等等,總之只要百度一下android推送關鍵字,就能看到很多的廠家。

這篇博文選擇的是極光推送(老闆選擇的平臺…),本文將從android客戶端服務端實現推送,讓大家對推送的全流程有一個完整的瞭解。

推送原理淺析

我一直認為,無論做那種開發,一定要思路先行,對要實現的功能有一個大致的理解,這樣才能以不變應萬變。

所以這部分,我個人認為是相比下面技術細節更為重要的內容,只要你理解的推送的大致的工作流程,那麼無論你再重新使用哪個推送平臺,都能得心應手。

平臺說明

目前提供送服務有非常多平臺,而其產品也能囊括訊息推送(還有實時聊天的sdk)、簡訊推送等服務,其平臺種類之多……各位小夥伴百度一下就知道了。其實平臺的選擇在前期並不是很重要(反正XX條推送內都免費),對於初次接觸推送的開發者而言,弄清楚推送的工作流程,才是不變的王道。

本篇博文的推送平臺採用極光推送

概念解釋

在正式介紹推送的實現方式之前,先來讓我理解一些基本的概念,這樣有助於我們後面的理解

  • 推送服務方
    提供推送介面及整合SDK,本文中的推送服務方就是極光推送

  • 專案伺服器
    每個正式的專案,肯定會有一個自己的後臺,用於為APP提供介面以及儲存APP產生的資料到伺服器的資料庫

    中。這裡的專案伺服器就是指安裝並開啟了wampServer的本機。

  • 推送請求
    通常情況下,我們會把跟推送相關的內容進行封裝(Json的方式),裡面會包含推送的內容(alert)、標題(title)、平臺(platform)等,詳細的選項可以參考推送服務方官網的文件,當然,推送請求的內容會因推送平臺的不同而有所差異,這裡以採用的推送服務方的官方文件為主。

  • 客戶端
    即發出推送請求或者接受推送訊息的一方,

推送的三種實現方式

客戶端直接向推送服務方傳送Http請求

最為簡單粗暴的一種方式,一般推送服務方都會給出一個呼叫推送服務的API,以極光推送為例,其post的呼叫地址為:

那麼在客戶端,直接使用Http,封裝推送請求所需要的引數,並向這個地址傳送請求

示意圖:
這裡寫圖片描述

從上圖可以看到,請求直接傳送給推送方,相關所有引數都需要在客戶端操作

優點:直接使用推送方的伺服器,所以無需配置,呼叫方便快捷
缺點:客戶端封裝大量引數,尤其在android和iOS開發同時存在時,微小的變動可能意味著兩邊大量程式碼的修改,不利於後期維護

專案伺服器通過Http轉發推送請求至推送服務方

(1)手機客戶端封裝關鍵引數(例如推送的type)
(2)專案伺服器接受請求,並再次封裝一些引數,例如推送訊息的titile和alert等
(3)專案伺服器作為客戶端,向推送方伺服器傳送Http請求;

首先應該明確的一點是,服務端和客戶端是一個相對的概念,可以簡單地提交請求的是客戶端,處理請求的是服務端。

此時客戶端的程式設計就會很輕鬆了(就是寫一條網路請求就可以了)。麻煩起來的是服務端,因為這二種方法的本質是:把本該由客戶端發起的相對複雜的Http請求交給了服務端完成一部分

那麼這種方法和第一種方法的區別是什麼呢?

第一種方法,傳送推送請求的客戶端是移動端裝置,在第二種方法中,傳送推送請求的客戶端,是專案伺服器,兩種方法接受推送請求的服務端,都是極光推送。客戶端不直接與推送伺服器打交道。

示意圖:(動圖太難做了(:з」∠)……還是簡單的示意圖吧)
這裡寫圖片描述

優點:專案伺服器對客戶端請求進行了一定封裝,當後期需求變動時,利於維護。
缺點:獨立開發的話在配置伺服器時有點麻煩……其他的看不出什麼明顯缺點(第二種方式可以和第三中方式做下對比)

專案服務端使用SDK進行功能整合

第三種實現方式和第二種在大致的工作流程上沒有什麼太大的區別,主要的不同在於,專案伺服器採用了第三方的SDK,在本地集成了之後,只需非常簡單的呼叫一行程式碼,那就能完成推送的功能(SDK的底層肯定還是網路請求,只不過做了相對完善的封裝)。

這裡寫圖片描述

可以看到極光推送為各種指令碼語言編寫的服務端都匹配了相應的sdk,還是比較方便的。

第三種方法的工作流程和第二種差不多,這裡就不在贅述了。

關於推送的種類概述

在實際使用的過程中,推送的物件大致分為如下幾種:

(1)無物件差別,全平臺推送
(2)無物件差別,特定平臺推送
(3)特定物件,全平臺推送
(3)特定群組,全平臺推送
(4)特定群組,特定平臺推送
(5)特定物件,特定臺對送

反正就是 物件、群組、平臺排列組合,根據專案需求進行設定。

一般比較常見的是特定物件推送,比如QQ訊息這種,就是針對某一使用者進行推送。

實現這種型別的推送,需要在客戶端啟動的時候為使用者設定一個Alias(相當於唯一識別符號),或者tag(表示使用者所屬群組),來進行特定推送。

關於推送的基本內容就介紹到這裡,更多詳細的內容,可以參考官方文件~

android客戶端初步實現

整合SDK說明

講道理,無論是那個第三方平臺,都會提供詳細的SDK開發文件給開發者,所以說只要開發者有點耐心,一點點按照官方文件上的去實現,遇到不懂的地方度娘一下,基本上就可以實現SDK的整合。

這裡我就不完全copy官網的文件,而是在官方文件的基礎上,用我自己的語言去描述一下sdk的整合過程,怕我描述有誤的小夥伴可以去參考更加權威的官方文件

當然隨著官網整合包的更新,可能我現在在博文裡寫的方法會過時,所以一切還是以官網的內容為準。

好了,廢話到此位置。

整合步驟

1、下載官方提供的SDK整合包

傳送門:客戶端 SDK 下載
然後解壓縮,看到如下目錄:
這裡寫圖片描述

同時我們在自己專案的src/main目錄下面新建一個資料夾jniLibs,將SDK包libs下面的CPU型別放入我們自己建立的jniLibs裡
這裡寫圖片描述

2、手動匯入SDK

官方提供了2中匯入的方法,一種是jCenter自動匯入,一種是手動匯入,這裡我們採用後者(前者的方法詳見官方文件)

(1)將lib目錄下的jpush-android-2.1.9.jar包匯入到專案的lib目標下
這裡寫圖片描述

(2)將jar包新增為主工程的依賴。右鍵jar包,點選add as Library,選擇app,確認。
當操作完畢後,我們可以通過FIle->project structure->app->Dependcies 檢視主工程新增依賴。

這裡寫圖片描述
可以看到已經新增到了主工程的依賴當中了

3、在極光的官網建立一個應用

我們要使用極光的推送服務,就必須在其官網建立一個開發者賬號(任何第三方推送平臺實際上都需要這麼做)

這裡寫圖片描述

建立的過程比較簡單,這裡就不詳細描述了,初學者需要稍微注意一下專案完整的包名

這裡寫圖片描述

4、編寫一個MyApplication類,初始化SDK

初始化SDK,沒什麼好說的

MyApplication

package com.example.dell.imooc_jpushdemo;

import cn.jpush.android.api.JPushInterface;

/**
 * Created by dell on 2016/9/23.
 */
public class MyApplication extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
        JPushInterface.setDebugMode(true);
        JPushInterface.init(this);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

5、配置 AndroidManifest.xml

這裡是我專案配置的 AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.dell.imooc_jpushdemo">

    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="23" />

    <!-- Required -->
    <permission
        android:name="com.example.dell.imooc_jpushdemo.permission.JPUSH_MESSAGE"
        android:protectionLevel="signature" />

    <!-- Required -->
    <uses-permission android:name="com.example.dell.imooc_jpushdemo.permission.JPUSH_MESSAGE" />
    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:name=".MyApplication"
        android:theme="@style/AppTheme">

        <!-- Required. For publish channel feature -->
        <!-- JPUSH_CHANNEL 是為了方便開發者統計APK分發渠道。-->
        <!-- 例如: -->
        <!-- 發到 Google Play 的APK可以設定為 google-play; -->
        <!-- 發到其他市場的 APK 可以設定為 xxx-market。 -->
        <!-- 目前這個渠道統計功能的報表還未開放。-->
        <meta-data android:name="JPUSH_CHANNEL" android:value="developer-default"/>
        <!-- Required. AppKey copied from Portal -->
        <meta-data android:name="JPUSH_APPKEY" android:value="52f7fd72d96df72e2a811d7c"/>


        <!-- Required -->
        <receiver
            android:name="cn.jpush.android.service.PushReceiver"
            android:enabled="true" >
            <intent-filter android:priority="1000">
                <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />
                <category android:name="com.example.dell.imooc_jpushdemo"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.USER_PRESENT" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
            <!-- Optional -->
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED" />
                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <data android:scheme="package" />
            </intent-filter>
        </receiver>
        <!-- Required SDK核心功能-->
        <activity
            android:name="cn.jpush.android.ui.PushActivity"
            android:configChanges="orientation|keyboardHidden"
            android:exported="false" >
            <intent-filter>
                <action android:name="cn.jpush.android.ui.PushActivity" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="com.example.dell.imooc_jpushdemo" />
            </intent-filter>
        </activity>
        <!-- Required SDK核心功能-->
        <service
            android:name="cn.jpush.android.service.DownloadService"
            android:enabled="true"
            android:exported="false" >
        </service>
        <!-- Required SDK核心功能-->
        <receiver android:name="cn.jpush.android.service.AlarmReceiver" />


        <!-- Required SDK 核心功能-->
        <!-- option since 2.0.5 可配置PushService,DaemonService,PushReceiver,AlarmReceiver的android:process引數 將JPush相關元件設定為一個獨立程序 -->
        <!-- 如:android:process=":remote" -->
        <service
            android:name="cn.jpush.android.service.PushService"
            android:enabled="true"
            android:exported="false" >
            <intent-filter>
                <action android:name="cn.jpush.android.intent.REGISTER" />
                <action android:name="cn.jpush.android.intent.REPORT" />
                <action android:name="cn.jpush.android.intent.PushService" />
                <action android:name="cn.jpush.android.intent.PUSH_TIME" />
            </intent-filter>
        </service>



        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

至此androidSDK的配置就完成了,現在我們可以去極光的去推送一下訊息,如果應用可以收到推送,這說明配置正確。

wampServer服務端配置

服務端這裡採用wampServer的方式,當然是處於簡單方便的考慮,還可以使用其他的指令碼語言來實現,而極光推送的官網也提供了相應的服務端SDK供大家使用

這裡的繼承方式採用官方提供的sdk(也就是本文介紹的第三種方法),當然,也可以使用PHP向推送方直接傳送HTTP請求。

配置推送SDK

極光官方建議使用composer進行SDK安裝,而且給了非常簡單的介紹
這裡寫圖片描述

接下來介紹一下composer的安裝。

通過composer配置

關於什麼是composer,我個人把它理解為android裡面的gradle,在android裡面,我們可以在gradle中新增一句 “compile XXX”就能輕鬆引入第三方庫,而composer的功能也是如此,composer是 PHP 用來管理依賴(dependency)關係的工具。你可以在自己的專案中宣告所依賴的外部工具庫(libraries),Composer 會幫你安裝這些依賴的庫檔案。

這裡簡單介紹一下composer的下載,不放心的小夥伴可以去Composer中文網相關檢視教程。

(1)從官網下載composer

一路next,安裝完畢後在cmd裡面輸入composer

這裡寫圖片描述

即說明下載成功。

(2)關於composer.phar

在查閱資料的時候,我看到了composer.phar檔案,後來研究了一下,得出了一些結論。

composer.phar 可以理解為composer的一個命令集合,不需要無需下載配置composer環境,只需要在PHP環境下,即可被使用,基本的使用方法是

php composer.phar XXXX

XXX表示composer的命令

而我們在這第一步下載的composer.exe,它實際做的一件事情是下載composer各種命令,並把composer新增到環境變數中(這也是為什麼我們安裝完畢後,在dos介面輸入composer能夠有反應的原因),其用法是:

composer XXX

發現沒,這裡的composer無需使用php,就能夠執行composer的命令

綜上述所述,如果你不想安裝composer.exe,下載一個composer.phar檔案,然後在PHP環境下執行就可以了,二者沒有太大的差別。

不過有一點需要注意的是,命令的執行目錄,一定要是當前的專案目錄(存放有composer.json)。

(3)編寫composer.json檔案

此檔案的作用主要用來宣告包之間的相互關係和其他的一些元素標籤。
接下來,我們來到專案目錄(我的是wamp/www/push)
在此目錄下新建一個叫 composer.json的檔案

這裡寫圖片描述

在此檔案裡面輸入後儲存,退出;

{
    "require": {
        "jpush/jpush": "v3.5.*"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5

(4)下載第三方庫

接下來,我們需要在cmd當中不斷的cd目錄,一直進入到我們當前的push目錄,這裡教大家一個簡單的方法。如果你裝了Git,那麼直接右鍵push目錄,點選git brash here 就能很方便地開啟dos介面。

鍵入下載的命令:

composer install

或者

php composer.phar install

二者的區別請見第二點

這裡寫圖片描述

在解釋上面問題之前,需要講講composer.lock這個檔案

在安裝完所有需要的包之後,composer會生成一張標準的包版本的檔案在composer.lock檔案中。這將鎖定所有包的版本。

使用composer.lock(當然是和composer.json一起)來控制你的專案的版本

這一點非常的重要,我們使用install命令來處理的時候,它首先會判斷composer.lock檔案是否存在,如果存在,將會下載相對應的版本(不會在於composer.json裡面的配置),這意味著任何下載專案的人都將會得到一樣的版本。

如果不存在composer.lock,composer將會通過composer.json來讀取需要的包和相對的版本,然後建立composer.lock檔案

這樣子就可以在你的包有新的版本之後,你不會自動更新了,升級到新的版本,使用update命令即可,這樣子就能獲取最新版本的包並且也更新了你的composer.lock檔案。

所以,第一次的話,使用install命令,之後的使用updata命令就好了。

全部下載完成後,我們的當前的專案目錄應該是這個樣子的。

這裡寫圖片描述

編寫推送介面

終於到了編寫介面的部分了

為了方便的載入包檔案,Composer自動生成了一個檔案 vendor/autoload.PHP,我們可以方便只有的使用它在任何你需要使用的地方。

新建一個test.php檔案 在裡面實現我們的推送邏輯。

<?php
//composer下載下來的第三方SDK都放在vendor資料夾中
//注意路徑
require 'vendor/jpush/jpush/autoload.php';

//接受post來的引數
$params=$_POST;

//建立應用的AppKey和master_secret,可以在極光應用後臺檢視
$app_key="52f7fd72d96df72e2a811d7c";
$master_secret="847d609885ec219f313b0c12";

/*
 * 官方程式碼
 * */
$client = new \JPush\Client($app_key, $master_secret);

$pusher = $client->push();
//設定平臺
$pusher->setPlatform('all');

$pusher->addAllAudience();

//唯一識別符號,暫不使用
//$pusher->addAlias($params['alias']);
// 簡單地給所有平臺推送相同的 alert 訊息

$pusher->setNotificationAlert('Hello, JPush');
try {
    $result=$pusher->send();
    var_dump($result);
} catch (\JPush\Exceptions\JPushException $e) {
    // try something else here
    print $e;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

官方文件裡有更詳細的介紹,相信大家結合上面的註釋應該是可以看懂的。

這個API的作用是向所有的客戶傳送一條訊息。

現在把wampServer執行起來,在瀏覽器輸入這個介面。

這裡寫圖片描述

如果呼叫成功,則說明介面正確~~

定向推送

到這裡,從客戶端到服務端的基本推送邏輯已經完成了,接下來我們做的一件事情就是實現定向的推送,即通過這個alias,將訊息傳送給指定的使用者

android客戶端改動

首先填寫一個佈局檔案MainActivity.xml

效果如下:
這裡寫圖片描述

比較簡陋,一個editText用於設定alias,一個editText用於輸入目標alias,還有一個Spinner用於選擇推送的型別。

xml程式碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.dell.imooc_jpushdemo.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <EditText
            android:id="@+id/et_set_alias"
            android:gravity="center"
            android:hint="設定alias"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/bt_set"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="設定"
           />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="當前alias:未設定"
            android:id="@+id/tv_alias"
            android:textSize="18sp"
            android:layout_marginTop="22dp" />


        <EditText
            android:id="@+id/et_alias"
            android:gravity="center"
            android:layout_marginTop="20dp"
            android:hint="輸入目標alias"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
        />

            <Spinner
                android:id="@+id/push_type"
                android:layout_width="match_parent"
                android:layout_height="30dp"
             />

            <Button
                android:id="@+id/bt_send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="傳送"
                android:layout_marginTop="23dp" />

            <TextView
                android:id="@+id/tv_result"
                android:text="推送結果"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
        />
        </LinearLayout>
</RelativeLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

接下來,我們編寫MainActivity當中的邏輯

public class MainActivity extends AppCompatActivity {
    //介面地址,根據本機的IP地址改動
    private final String url="http://192.168.0.128/push/test.php";
    //返回的結果
    private TextView tvResult;
    private Button btSend; //傳送推送請求
    private Spinner mSpinner; //選擇推送方式
    //推送種類
    private String pushType;
    //spinner的介面卡
    private ArrayAdapter<String> adapter;
    //設定alias的按鈕
    private Button btSetAlias;
    //顯示使用者設定的alias
    private TextView tvAlias;
    private String alias;

    //更新UI
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            StringBuffer sb = (StringBuffer) msg.obj;
            tvResult.setText(sb.toString());
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mSpinner= (Spinner) findViewById(R.id.push_type);
        tvResult= (TextView) findViewById(R.id.tv_result);
        btSend= (Button) findViewById(R.id.bt_send);
        btSetAlias= (Button) findViewById(R.id.bt_set);
        tvAlias= (TextView) findViewById(R.id.tv_alias);
        //spinner內的文字
        String[] strings=getResources().getStringArray(R.array.push_type);
        List<String> list=new ArrayList<>();
        for(String s:strings){
            list.add(s);
        }

        adapter=new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_spinner_item,list);
        //第三步:為介面卡設定下拉列表下拉時的選單樣式。
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        //第四步:將介面卡新增到下拉列表上
        mSpinner.setAdapter(adapter);

        mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                pushType=adapter.getItem(i);
                    /* 將mySpinner 顯示*/
                adapterView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
                adapterView.setVisibility(View.VISIBLE);
            }
        });

        //設定alias
        btSetAlias.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alias=((EditText)findViewById(R.id.et_set_alias)).getText().toString();
                //呼叫SDK介面
                JPushInterface.setAlias(getBaseContext(),alias, new TagAliasCallback() {
                    @Override
                    public void gotResult(int i, String s, Set<String> set) {
                        tvAlias.setText("當前alias:"+alias);
                        Toast.makeText(MainActivity.this, "設定成功", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });

        btSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sendRequest();
            }
        });
    }

    private void sendRequest() {
        new Thread(new Runnable() {
            @Override
            public void run() {

                String alias=((EditText)findViewById(R.id.et_alias)).getText().toString();
                try {
                    // 傳遞的資料
                    String data ="&alias="+URLEncoder.encode(alias,"UTF-8")
                            +"&push_type="+URLEncoder.encode(pushType,"UTF-8");
                    URL httpUrl = new URL(url);
                    HttpURLConnection urlConnection = (HttpURLConnection) httpUrl.openConnection();
                    urlConnection.setRequestMethod("POST");

                    // 設定請求的超時時間
                    urlConnection.setReadTimeout(5000);
                    urlConnection.setConnectTimeout(5000);

                    //呼叫conn.setDoOutput()方法以顯式開啟請求體
                    urlConnection.setDoOutput(true); // 傳送POST請求必須設定允許輸出
                    urlConnection.setDoInput(true); // 傳送POST請求必須設定允許輸入

                    //setDoInput的預設值就是true
                    OutputStream ost = urlConnection.getOutputStream();

                    PrintWriter pw = new PrintWriter(ost);
                    pw.print(data);
                    pw.flush();
                    pw.close();

                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    StringBuffer sb = new StringBuffer();
                    String s;
                    while ((s = bufferedReader.readLine()) != null) {
                        sb.append(s);
                        Log.d("111", "run: "+sb.toString());
                    }
                    Message msg = new Message();
                    msg.obj = sb;
                    handler.sendMessage(msg);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136

R.array.push_type裡面的內容:(在res/value/arrays.xml中配置,如果沒有這個xml檔案,手動建立)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="push_type">
        <item>push Type</item>
        <item>new_task</item>
        <item>send_task</item>
        <item>get_task</item>
        <item>finish_task</item>
    </string-array>
</resources>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
save_snippets.pngsave_snippets.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

註釋都比較清