Android Research‎ > ‎

GCM

GCM is Google Cloud Messaging for Android.

- 前情提要 -


基本上概念跟之前推的C2DM是一樣的,都是push notification的機制,
只不過C2DM已經不繼續維護了,現在改成使用GCM。
整個架構上比較完整的介紹: http://developer.android.com/guide/google/gcm/gcm.html
他們的差別可以參考官網上的說明: http://developer.android.com/guide/google/gcm/c2dm.html#diffs


簡單講一下整個機制運作的流程 :

GCM流程圖


(1) APP跟Google GCM Server註冊
首先我們開發的手機APP必須先跟Google GCM Server註冊
這邊會需要一個Sender ID的東西,告訴GCM Server現在是哪個人要來使用這GCM服務,
而Sender ID在下方的說明中,會跟大家說如何拿到這個ID,

(2) GCM Server回傳RegID
手機上的APP註冊成功後GCM Server會丟回一個Reg ID給APP,
這個Reg ID就是要給我們等一下架設的第三方Server識別所用,
這樣我們在發送訊息的Server端才能知道這訊息要發送給哪些手機裝置。

(3) APP跟我們架設Server註冊
這邊當然是要先架設發送訊息的主控Server,
透過下方的說明中跟Google Service拿到的API KEY,
取得使用GCM服務的許可。
剛剛APP拿到Reg ID後,必須傳送到我們架設發送訊息的Server,
並且把它存起來,當然如果APP要丟其他的東西過來Server也是可以。
所以這邊Server端會需要寫一些Servlet或是Service讓APP能register或unregister。

(4) 我們架設Server發送訊息
我們架設的Server要發送訊息,
必須透過Google GCM Service,
所以要跟它說你要丟給誰,也就是API KEY、Reg ID以及message,
下方的說明中會解釋如何拿到API KEY,有這KEY我們才能使用Google Service。

(5) Google GCM Service發送訊息
一旦我們的server請求GCM發送時,
它並不保證多久會送達、會不會miss、也不保證訊息的順序
所以接下來就必須等待GCM傳送訊息到擁有這RegID的手機上了。


- APP實作 -



實作上原本在C2DM機制下是要利用ClientLogin或是OAuth2取得Auth token,不過GCM這邊改成使用API KEY即可,
所以我們需要先拿到API Key,方法就是建立一個Google API project。

接下來的步驟,目的是要取得  Sender ID  跟  API KEY
Sender ID是要放在Android App裡面,拿去跟Google的GCM Server註冊,然後回傳一個RegID。
API KEY是要給我們自己的Server用的,因為我們的Server要去叫Google的GCM Server幫忙傳送訊息給Device。


=>建立一個Google API project
步驟可以參考官網上的說明: http://developer.android.com/guide/google/gcm/gs.html#create-proj
首先登入
https://code.google.com/apis/console

登入成功之後,上方網址列可看到
https://code.google.com/apis/console/#project:4815162342

像這樣的URL,其中最後的那串數字就是project ID也是sender ID
這個sender ID在等一下實作Android application會用到。


在Google Console網頁的左邊有個Service部分,右邊的清單中可以找到 Google Cloud Messaging這個服務,把它開啟。
接下來在左邊API Access地方,點擊右邊的Create new Server key按鈕
輸入你的 Server IP 當做白名單就完成了,網頁下方就能看到API key
如此一來,也完成跟Google說要使用GCM的服務囉。




在開始實作Client APP之前,必須先透過Android SDK Manager
安裝Extras > Google Cloud Messaging for Android Library
有了這些Halper Libraries,就可以開始撰寫Android Application囉。

先提供一下參考說明: http://developer.android.com/guide/google/gcm/gs.html#android-app

這邊很簡單,先把manifest搞定

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.my.testgcm"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MyActivity"
            android:label="@string/title_activity_my" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="my" />
        </activity>
       
        <receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
          <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="com.my.testgcm" />
          </intent-filter>
        </receiver>
       
        <service android:name=".GCMIntentService" />
    </application>
   
    <permission android:name="com.my.testgcm.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.my.testgcm.permission.C2D_MESSAGE" />
    <!-- App receives GCM messages. -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <!-- GCM connects to Google Services. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- GCM requires a Google account. -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <!-- Keeps the processor from sleeping when a message is received. -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />

</manifest>

這樣就搞定囉 ~~
接下來只要建立一個GCMIntentService即可
只要在com.my.testgcm底下建立GCMIntentService並且extends GCMBaseIntentServicer即可,
這邊務必先把extras\google\gcm\gcm-client\dist\gcm.jar加入classpath
目的是希望GCMBroadcastReceiver收到GCM的通知時,我們只需要去實作service本身預留的四個
callback methods即可。

最後只要在我們的Activity加入

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        //verifies that the device supports GCM and throws an exception if it does not

        GCMRegistrar.checkDevice(this);
        //this method is only necessary when you are developing the application;
        //once the application is ready to be published, you can remove it
        GCMRegistrar.checkManifest(this);


       
        final String SENDER_ID = "1234567890";//請參考上方取得SENDER_ID部分
        final String regId = GCMRegistrar.getRegistrationId(this);
        if (regId.equals("")) {
          GCMRegistrar.register(this, SENDER_ID);
        }
        else {
          Log.e("de", "Already registered regId = " +regId);
        }

    }


一切就完成了,其實這邊跟以前不一樣的部份應該就是之前都要自己做,現在framework都幫你封裝實作好。

為了加快開發速度,我使用當初在安裝Google Cloud Messaging for Android Library時,
Google提供的範例程式,他位置是在extras\google\gcm\sample中client部分,
只要impoet到Eclipse後修改SenderID跟server URL就完成。

- Server實作 -

在實作server端的部份,我們參考官網的demo範例

http://developer.android.com/guide/google/gcm/demo.html#server-setup

這邊我們也是使用範例程式,直接拿extras\google\gcm\sample中server部分,
修改API KEY之後,使用ant指令產生war檔,放到Tomcat底下就完成囉。
這Server端的範例是沒有使用DB的,純粹是demo用,不過trace一下大致上都能理解整個流程。





- 後記 -


在開發專案時,因為專案需要,所以我採用Android library project reference方式,

實作的service類別是在放在library project底下的一個位置,

但是我主要的project要reference這個library project時候也會用到GCM機制,

在define這專案的manifest時候,receiver裡面的category這邊要特別注意,

如果按照原本宣告的方式,

當接收到GCM message時,receiver會找錯service類別的位置

原因跟解決方式如下:

http://dexxtr.com/post/28188228252/rename-or-change-package-of-gcmintentservice-class

主因是兩個專案的package name不同,

造成reveiver沒有去找放在library project的service而跑去找自己package底下的位置,

解決方式就是自己做個receiver並且override getGCMIntentServiceClassName

強迫接收到message時能執行正確的service類別。



最近開發專案時, 遇到無法取得token的問題,
從 GCM 拿到的訊息是在 GCMBaseIntentService 的 onError 裡面
顯示 " AUTHENTICATION_FAILED
花了不少時間找問題, 後來在GCM官網上看到


Google User AccountFor GCM to work, the mobile device must include at least one Google account if the device is running a version lower than Android 4.0.4.

猜到了嗎? 原本我的裝置有登入Google帳號,  不過因為更改密碼等因素,
造成這台裝置上已經沒有可用的帳號  ~"~






- 其他參考 資料 -


http://m4ttch.wordpress.com/2012/07/17/%E7%AD%86%E8%A8%98-google-cloud-messaging/













Comments