Google Cloud Messaging for Android(GCM)を利用するためのメモ。
メモ:
- 最大4kbのペイロード・データのメッセージを送出可能
- Android2.2以上かつGooglePlayStoreがインストールされた端末が必要
- Android3.0以前の端末ではGoogleアカウントがセットアップされている必要がある
- GCMはGoogle Play serviceに組み込まれた(com.google.android.gms.gcm)
- 従来のAPI群は非推奨に(com.google.android.gcm)
- GoogleCloudMessaging(API)の利用にはGoogle Play services version 3.1以上が必要
- メッセージ送信時に対象デバイスがオフラインであってもGCMはこれをキューイング/ストア>再送する機能を持つ
- 3rdPartyサーバはexponential backoffの方式を組み込み、GCMサーバと通信すること
- GCMメッセージはアプリ固有のPermission付きBroadcastIntent経由で通知される
- GCMメッセージを受信すると対象アプリが起動されるため、メッセージ監視のためにアプリ起動し続ける必要はない
- メッセージ処理はWakeLockを取得してService上で実行するが吉
- GCMメッセージを受信したくない場合はunregisterも可能
- Genymotionを使用する場合のBackendサーバアドレスは10.0.3.2
GCM基本フロー
- アプリケーションはGCMを有効化するための登録を行う
- 3rdPartyサーバはデバイス向けメッセージをGCMに送信
- アプリケーションはGCMからメッセージを受信する
準備するもの
- Google API Projectの作成Google Developers Console
- Project Numberを控える(GCM sender IDとして使用.)
- API \& auth.からGoogle Cloud Messaging for Androidを有効化.
- GCMのServer Keyを作成しAPI Key取得(3rdPartyサーバとGCMサーバ間認証で使用)参考:Obtaining an API Key
3rdPartyサーバの作成
GCMサーバ(GCM connection server)とやりとりするサーバを作成する必要があります。
Implementing GCM Server
App Engine Backend with GCM
試験用途であればApp Engine Backend with Google Cloud Messagingで手軽にGCMバックエンドを作成できます。
利用するには新規ModuleとしてBackendモジュールを作成します(AndroidStudio0.8.2以降)。
Backendモジュールの作成から実行までの詳細手順は下記を参考。
“App Engine Backend with Google Cloud Messaging” Template
Backendモジュール導入に必要な作業は次の通りです。
- 取得済みGCMのAPI Keyを登録
- build.gradleの編集
- Backendサーバへのデバイス登録処理の実装
GCM API Keyを登録
Backendモジュールを作成したらGCMのAPI Keyを登録します。
API Keyは<backend>/src/main/webapp/WEB-INF/appengine-web.xml
に定義されているので、
これを取得済みのものに置き換えます。
<property name="gcm.api.key" value="YOUR_KEY_HERE"/>
YOUR_KEY_HEREを取得済みのAPI Keyに置換。
<property name="gcm.api.key" value="AIza..."/>
これでAPI Keyの登録は完了です。
build.gradleの編集
(この作業はAndroidStudio v0.8.2より後のバージョンでは不要になるかもしれません)
AndroidStudio v0.8.2でBackendモジュールとメインとなるappモジュールを関連づけすると、
ビルドで問題(preDexLibraryタスクでOutOfMemoryやIllegalArgumentException)が発生します。
これを回避するためにappからappengine-endpoints(-deps)ライブラリのコンパイル指定をコメントアウトします。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:19.0.+' compile 'com.google.android.gms:play-services:5.0.77' // appengine-endpoints(-deps)はBackendモジュールに含まれているため、appモジュールでの個別指定は不要 // compile 'com.google.appengine:appengine-endpoints:1.9.1' // compile 'com.google.appengine:appengine-endpoints-deps:1.9.1' compile project(path: ':gcmbackend', configuration: 'android-endpoints') }
Backendサーバへのデバイス登録処理の実装
下記のGcmRegistrationAsyncTaskクラスを取り込みます。
2.2. Registering devices with Google Cloud Messaging backend
GcmRegistrationAsyncTaskに定義されているSENDER_IDを自分のもの(GCM APIのProject Number)に置換します。
また、BackendサーバのURIを必要に応じて変更します。
- Android Emulatorを使用している場合:
http://10.0.2.2:8080/_ah/api/
(変更なし) - Genymotionを使用している場合:
http://10.0.3.2:8080/_ah/api/
Android Emulatorにおける10.0.2.2はホストループバックインターフェイスのエイリアスです(localhost)。
Genymotionでは10.0.3.2がこれにあたります。
全ての作業が終わったらBackendモジュールを実行し、ローカルサーバを起動します.
localhost:8080でGCMを送信するフォームが表示されます。
適当なActivityからGcmRegistrationAsyncTaskのexecuteを実行するとBackendサーバに端末のRegistrationIDが登録されます。
RegistrationID登録後にGCM送信フォームからテキストを送信すると端末にPush通知が届きます。
Androidアプリケーションの作成
GCMクライアントとなるAndroidアプリケーションを作成する場合はGoogleCloudMessaging APIの使用が推奨されています。
Google Play Serviceのセットアップ
アプリケーションの作成にはGoogle Play Serviceを使用します。
アプリケーションはGoogle Play ServiceのResourceにアクセスするため、単純に.jarを参照するだけでは動作しません。
AndroidStudioの場合はbuild.gradleのdependencyセクションに次を追記します。
dependencies { compile "com.google.android.gms:play-services:3.1.+" }
GCMを使用するにはGoogle Play Service3.1以上である必要があります。
AndroidManifest.xmlの編集
次のPermissionを追加します。
com.google.android.c2dm.permission.RECEIVE
: GCMサービスへの登録とメッセージ受信に必要android.permission.INTERNET
: 3rdPartyサーバへのRegistrationIDの登録に必要android.permission.WAKE_LOCK
: (optional)メッセージ受信時のWakeLock取得に必要YourApplicationPackage + ".permission.C2D_MESSAGE"
: 他アプリからGCMへ登録されることやメッセージを横取りされるのを防ぐのに必要com.google.android.c2dm.intent.RECEIVE
: categoryに自アプリのパッケージ名を指定する。GCMメッセージ受信に必要android.permission.GET_ACCOUNTS
: GCMに必要なGoogleアカウント情報取得に必要(Android4.0.4以前で必要)
a<!-- AndroidManifest.xml --> <manifest package="com.example"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <!-- Android4.0.4以前をサポートする場合に必要 --> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <!-- YourApplicationPackage + ".permission.C2D_MESSAGE" --> <permission android:name="com.example.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="com.example.permission.C2D_MESSAGE" />
GCMの有効化
アプリケーションが初めてGCMを利用する前にGoogleCloudMessaging(API)のregister()
メソッドを使ってGCMサービスへ登録する必要があります。
このメソッドはRegistrationIDを返します。参考:GoogleCloudMessaging
GCMへサービス登録する前にGoogle Play Serviceの状態をチェックします。
Google Play Serviceが古いバージョンである場合、Google Play Serviceの更新をユーザに促します。
アプリ起動中にGoogle Play Serviceがダウングレードされるケース等を考慮して、バージョンチェックはonResume()
で行います。
@Override protected void onResume() { super.onResume(); try { PlayServiceUtil.updatePlayServiceIfNeeded(this, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { MyActivity.this.finish(); } }); } catch (PlayServiceUtil.PlayServiceException e) { // Play Serviceが使用できない致命的状態 Log.e(TAG, "Play Service is not available."); this.finish(); } } public static void updatePlayServiceIfNeeded(Activity activity, DialogInterface.OnCancelListener cancelListener) throws PlayServiceException { final int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity); switch (status) { case ConnectionResult.SUCCESS: return; case ConnectionResult.SERVICE_DISABLED: case ConnectionResult.SERVICE_INVALID: case ConnectionResult.SERVICE_MISSING: case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED: Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, activity, 0); if (cancelListener != null) { dialog.setOnCancelListener(cancelListener); } dialog.show(); return; default: throw new PlayServiceException("Play Service is not available. status=" + status); } }
メッセージ送信
3rdPartyサーバ(以降”サーバ”)がメッセージ送信する時のシーケンス
- サーバはGCMにメッセージを送信
- GCMサーバは送信対象のデバイスがオフラインであればメッセージをキューイング/ストアする
- GCMサーバは送信対象のデバイスがオンラインになればメッセージを送信する
- デバイスはメッセージを受信すると配送すべきアプリケーションに向けてメッセージをブロードキャストする。
配送されるのはアプリ固有のPermissionが設定されたBroadcastIntent。 - メッセージ処理が些末なものでない場合はPowerManager.WakeLockを取得してService上で実行する
メッセージ受信
デバイスがGCMメッセージを受信した時のシーケンス
- システムは、受信したメッセージからKey/Valueペアを展開
- システムは、com.google.android.c2dm.intent.RECEIVEのIntentとextraにKey/Valueデータを載せてアプリケーションに連携
- アプリケーションはIntentからKey/Valueを展開してデータを受け取る
参考サイト:
1. Google Cloud Messaging -android developers-