1. 程式人生 > >google的GCM推送使用簡介

google的GCM推送使用簡介

轉載請註明出處:http://blog.csdn.net/newhope1106/article/details/54709916

GCM即Google Cloud Messaging,主要用於訊息推送的,即使在應用沒有起來的情況下,客戶端也能通過GCM收到來自伺服器的訊息。GCM支援Android、IOS和Chrome。由於GCM需要google service支援,在國內基本不能用,經常會斷線,不過最近專案要求,只在美國上線該專案,因此可以採用GCM實現推送的方式,國內相關文章較少,特意整理了一下客戶端使用的官方文件。

首先來看看目前應用不啟動實現推送的方式有哪些:

1.使用Google自帶的GCM實現推送

2.採用監聽開機廣播的方式,啟動後臺服務,為了防止被殺死,採用多程序的方式,監聽服務是否被殺,被殺之後,把它拉起來(比較流氓)

3.採用第三發方案,如友盟、極光、信鴿

國內第二種和第三種用得比較多,本文主要講解第一種方案,也就是GCM,以下內容均來自官網

一、概述

GCM可以讓開發者在客戶端和伺服器之間傳遞訊息,有2種方式實現訊息推送,一種是xmpp,它即可讓伺服器把訊息推送給客戶端,也可讓客戶端把訊息推送給伺服器,另一種方式是http,只能伺服器將訊息推送給客戶端,以下是其架構圖。


GCM伺服器接收應用伺服器的訊息,然後再把訊息轉發給客戶端,伺服器端根據自己的需要實現xmpp或者http介面,和GCM伺服器進行通訊,客戶端想要接收訊息,需要使用GCM提供的API。

二.客戶端使用GCM

1.使用限制:

a.最低要求Android 2.2+的裝置,並且安裝了Google應用商店

b.想要使用GCM新特性,要求Android 2.3+

c.低於Android 4.0.4版本,需要Google賬號,Android 4.0.4+不需要

2.客戶端使用GCM流程

和使用一般的sdk類似,首先需要在官網註冊自己的應用,獲取一個appid,出於安全要求,需要在本地使用這個appid去獲取動態token,需要把token上傳給伺服器,每隔一段時間token可能會失效,需要去重新獲取token。按照上面的過程我們來看看怎麼使用的。以下針對Android Studio開發的。

(1)官網註冊應用

首先我們需要到這個網址:https://console.firebase.google.com/ 去註冊自己的應用,按照相關步驟操作之後,點選下載配置檔案,會下載一個叫google-services.json的檔案,把它放到自己的專案的app/目錄下。

(2)新增配置檔案解析外掛依賴

上述下載的google-services.json需要外掛進行解析,要在專案中按照下面步驟新增依賴

a.在專案級別(project-level)的build.gradle新增下面依賴

classpath 'com.google.gms:google-services:3.0.0'

b.在自己的應用級別(app-level)的build.gradle新增下面外掛

apply plugin: 'com.google.gms.google-services'

(3)新增GCM依賴

程式碼中需要用到gcm的api,因此需要新增gcm的依賴,版本請使用最新的版本,下面只是示範

dependencies {
  compile
"com.google.android.gms:play-services-gcm:10.0.0"}

(4)修改AndroidMenifest.xml檔案

a.新增許可權,因為我們不允許其他的應用接收和傳送屬於自己應用的訊息,因此新增許可權遮蔽其他應用,許可權格式:<application-package-name> + ".permission.C2D_MESSAGE"

b.定義一個GcmReceiver接收器,用來接收發送給應用的訊息,需要新增com.google.android.c2dm.permission.SEND許可權

c.定義GcmListenerService伺服器,用來處理各種不同的下發資訊,上髮狀態,自動顯示通知等

d.定義一個整合InstanceIDListenerService的服務,用來獲取、重新整理token

e.額外的,可以新增android.permission.WAKE_LOCK許可權,保證訊息到達的時候,可以得到及時處理

以下是一個demo

<manifestpackage="com.example.gcm" ...><uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="17"/><uses-permissionandroid:name="android.permission.WAKE_LOCK"/>

    <permission android:name="
<your-package-name>.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="
<your-package-name>.permission.C2D_MESSAGE" />

   
<application ...><receiverandroid:name="com.google.android.gms.gcm.GcmReceiver"android:exported="true"android:permission="com.google.android.c2dm.permission.SEND"><intent-filter><actionandroid:name="com.google.android.c2dm.intent.RECEIVE"/><categoryandroid:name="com.example.gcm"/></intent-filter></receiver><serviceandroid:name="com.example.MyGcmListenerService"android:exported="false"><intent-filter><actionandroid:name="com.google.android.c2dm.intent.RECEIVE"/></intent-filter></service><serviceandroid:name="com.example.MyInstanceIDListenerService"android:exported="false"><intent-filter><actionandroid:name="com.google.android.gms.iid.InstanceID"/></intent-filter></service><serviceandroid:name="gcm.play.android.samples.com.gcmquickstart.RegistrationIntentService"android:exported="false"></service></application></manifest>

如果是android 4.4之前的版本,需要在receiver中新增的intent-filter中新增下面的action

<action android:name="com.google.android.c2dm.intent.REGISTRATION" />

3.客戶端獲取、重新整理token

(1)先來看看獲取token的介面

String authorizedEntity = PROJECT_ID;// Project id from Google Developer ConsoleString scope ="GCM";// e.g. communicating using GCM, but you can use any// URL-safe characters up to a maximum of 1000, or// you can also leave it blank.String token =InstanceID.getInstance(context).getToken(authorizedEntity,scope);

(2)token的更新

在前面有提到AndroidMenifest.xml中註冊一個繼承InstanceIDListenerService的服務,看看具體的實現

publicclassMyInstanceIDServiceextendsInstanceIDListenerService{publicvoid onTokenRefresh(){
    refreshAllTokens
();}privatevoid refreshAllTokens(){// assuming you have defined TokenList as// some generalized store for your tokensArrayList<TokenList> tokenList =TokensList.get();InstanceID iid =InstanceID.getInstance(this);for(tokenItem : tokenList){
      tokenItem
.token =
        iid
.getToken(tokenItem.authorizedEntity,tokenItem.scope,tokenItem.options);// send this tokenItem.token to your server}}}

第一次獲取token,雖然沒有獲取過token,但本質還是重新整理,都是呼叫onTokenRefresh介面,並且把獲取的token傳送給伺服器。

上面的處理可以最好用一個IntentService來非同步處理,不要放在主執行緒中,上述給一個使用範例而已。

(3)InstanceID

上面我們看到,獲取token的時候,首先需要InstanceID,當裝置上線的時候,Instance ID Service會分配一個InstanceID, InstanceID是由一對公鑰和私鑰共同維護的,私鑰儲存在本地,公鑰由Instance ID Service註冊產生。可以通過呼叫geId()方法,隨時更新InstanceId,因為生成的token都是依賴這個InstanceID的。

String iid =InstanceID.getInstance(context).getId();

你也可以刪除一個InstanceID,那麼對應的所有token都會失效,用新的InstanceID生成新的token

InstanceID.getInstance(context).deleteInstanceID();String newIID =InstanceID.getInstance(context).getId();

(4)Instance ID 的生命週期圖


4.客戶端接收伺服器下發資訊

a.伺服器可以通過HTTP(單向)和XMPP(雙向)傳送資訊,看看下面的demo

HTTP POST Request

https://gcm-http.googleapis.com/gcm/sendContent-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA{"data":{"score":"5x1","time":"15:10"},"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."}

XMPP Message

<messageid=""><gcmxmlns="google:mobile:data">
    { "data": {
      "score": "5x1",
      "time": "15:10"
    },
    "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
  }
 
</gcm></message>

b.客戶端處理下發訊息

伺服器傳送的訊息,GCM會將接收到的訊息轉發給客戶端,在前面的AndroidManifest.xml中,我們定義了一個GcmListenerService來處理訊息,可以自己繼承GcmListenerService並且覆蓋onMessageReceived方法。

@Overridepublicvoid onMessageReceived(Stringfrom,Bundle data){String message = data.getString("message");Log.d(TAG,"From: "+from);Log.d(TAG,"Message: "+ message);if(from.startsWith("/topics/")){// message received from some topic.}else{// normal downstream message.}// ...}

5.客戶端上發訊息

publicvoid onClick(finalView view){if(view == findViewById(R.id.send)){newAsyncTask<void, void,="" string="" style="box-sizing: inherit;">(){@OverrideprotectedString doInBackground(Void...params){String msg ="";try{Bundle data =newBundle();
                    data
.putString("my_message","Hello World");
                    data
.putString("my_action","SAY_HELLO");String id =Integer.toString(msgId.incrementAndGet());
                    gcm
.send(SENDER_ID +"@gcm.googleapis.com", id, data);
                    msg
="Sent message";}catch(IOException ex){
                    msg
="Error :"+ ex.getMessage();}return msg;}@Overrideprotectedvoid onPostExecute(String msg){
                mDisplay
.append(msg +"\n");}}.execute(null,null,null);}elseif(view == findViewById(R.id.clear)){
        mDisplay
.setText("");}}</void,>

主要是利用了gcm的send介面,上述需要伺服器支援xmpp

6.伺服器端的實現

有興趣的可以參考google的程式碼demo