Symfoware

Symfowareについての考察blog

Cordova GCMから送信したAndoroidのプッシュ通知を受け取るアプリケーションの作成

CordovaでAndoroidのプッシュ通知を受け取ってみます。



※2015/3/1 追記

通知領域に表示する方法
Cordova GCMからのプッシュ内容を通知領域に表示する




Google Cloud Messaging



プッシュ通知の仕組みはこちらがとても参考になりました。
Androidのプッシュ通知を調べてみた

GCM(Google Cloud Messaging)を利用して、各端末に通知を行うそうです。
下準備として、GCMへの登録が必要になります。

http://developer.android.com/google/gcm/gs.html

まず、Google Developers Consoleへログインしろとのこと。

幸い、以前Google App Engineへ登録した時のアカウントがあるので、
このとき作成したアカウントとプロジェクトを使うことにしました。
Google App Engineに登録し、アカウントを発行してもらう

Google Developers Consoleを表示します。

573_01.png


プロジェクト名をクリック。
[APIと認証] - [API]を選択し、APIの絞り込みに「Android」と入力。
「Google Cloud Messaging for Android」を探します。

右側の[ステータス]がOFFになっているので、クリックして有効にします。

573_02.png


ステータスがONになりました。

573_03.png




次に、APIの設定を行いAPIキーを取得します。
[APIと認証] - [認証情報]を選択。
「公開 API へのアクセス」の「新しいキーを作成」をクリックします。

573_04.png


どの種類のキーを作成するか確認されます。
一番左の「サーバーキー」を選択します。

573_05.png


サーバーキーを受け付けるIPアドレスの指定画面が表示されます。
空白にすることで、全てのIPアドレスからのリクエストを受け付けます。

573_06.png


ドキュメントによっては、「0.0.0.0/0」を指定しろと書いてあったのですが、
これだと認証エラーになりました。

573_07.png


こちらがヒントになりました。
Why is my GCM API key invalid?


これでGCM側の設定は終了です。
プログラムで必要になる値を控えておきます。

1つは「Sender ID」
これは、画面上「プロジェクト番号」と表示されている数値です。

573_08.png


もう1つは「API KEY」
これは、GCMでAPIを有効にした時に表示されるAPIキーになります。

573_09.png




エミュレーターの設定変更



エミュレーターでは動作テストできないかな?と思っていたのですが、
こちらを参考に設定を変更すれば動作しました。

GCMテスト用のAndroid Virtual Device (AVD) の準備


Android SDK Managerで「Google APIs(x86 System Image)」をインストールしておきます。

573_10.png


エミュレーターの「Target」を「Google APIs(x86 System Image)」に変更。

573_11.png


これでエミュレーターの準備完了です。




プラグインのインストールとプログラム



PushPlugin

こちらが有名どころのようです。
せっかくなので、新規プロジェクトの作成からおさらいです。

プロジェクトを作成してディレクトリに移動


$ cordova create test02 com.fc2.blog68.symfoware Test02
$ cd test02




プラットフォーム追加


$ cordova platforms add android




依存しているdeviceプラグインとデバッグ用にconsoleプラグインを追加


$ cordova plugin add org.apache.cordova.device
$ cordova plugin add org.apache.cordova.console




最後にPushPluginをインストールします。


$ cordova plugin add https://github.com/phonegap-build/PushPlugin.git




githubのソースそのままですが、index.htmlに処理をまとめてみました。
senderIDは、上記で取得した「Sender ID(プロジェクト番号)」を指定します。

※実行にはlibフォルダにjQueryが必要です。


  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <meta charset="utf-8" />
  5.     <meta name="format-detection" content="telephone=no" />
  6.     <meta name="msapplication-tap-highlight" content="no" />
  7.     <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
  8.     <title>Push!</title>
  9. </head>
  10. <body>
  11.     <h1>Pushテスト</h1>
  12.     <ul id="app-status-ul"></ul>
  13.         
  14.     
  15. <script type="text/javascript" src="cordova.js"></script>
  16. <script type="text/javascript" src="lib/jquery-2.1.3.min.js"></script>
  17. <script type="text/javascript">
  18. $(function() {
  19.     var pushNotification;
  20.     document.addEventListener("deviceready", function(){
  21.         pushNotification = window.plugins.pushNotification;
  22.         
  23.         // Android 通知の登録が成功した場合
  24.         var successHandler = function successHandler(result) {
  25.             $("#app-status-ul").append('<li>result = ' + result + '</li>');
  26.         };
  27.         
  28.         // iOS 通知の登録が成功した場合
  29.         function tokenHandler (result) {
  30.             alert('device token = ' + result);
  31.         }
  32.         
  33.         // 通知の登録が失敗した場合
  34.         var errorHandler = function(error) {
  35.             $("#app-status-ul").append('<li>error = ' + error + '</li>');
  36.         };
  37.         
  38.         $("#app-status-ul").append('<li>registering ' + device.platform + '</li>');
  39.         if ( device.platform == 'android' || device.platform == 'Android' || device.platform == "amazon-fireos" ){
  40.             pushNotification.register(
  41.             successHandler,
  42.             errorHandler,
  43.             {
  44.                 // ここをSender ID(プロジェクト番号)に変更
  45.                 "senderID":"1234567890",
  46.                 "ecb":"onNotification"
  47.             });
  48.         } else {
  49.             pushNotification.register(
  50.             tokenHandler,
  51.             errorHandler,
  52.             {
  53.                 "badge":"true",
  54.                 "sound":"true",
  55.                 "alert":"true",
  56.                 "ecb":"onNotificationAPN" // iOSは試せないので一旦保留
  57.             });
  58.         }
  59.     
  60.     });
  61. });
  62. // androidの通知
  63. function onNotification(e) {
  64.     $("#app-status-ul").append('<li>EVENT -> RECEIVED:' + e.event + '</li>');
  65.     switch( e.event ) {
  66.     case 'registered':
  67.         if ( e.regid.length > 0 )
  68.         {
  69.             $("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
  70.             // Your GCM push server needs to know the regID before it can push to this device
  71.             // here is where you might want to send it the regID for later use.
  72.             console.log("regID = " + e.regid);
  73.         }
  74.     break;
  75.     case 'message':
  76.         // if this flag is set, this notification happened while we were in the foreground.
  77.         // you might want to play a sound to get the user's attention, throw up a dialog, etc.
  78.         if ( e.foreground )
  79.         {
  80.             $("#app-status-ul").append('<li>--INLINE NOTIFICATION--' + '</li>');
  81.             // on Android soundname is outside the payload.
  82.             // On Amazon FireOS all custom attributes are contained within payload
  83.             var soundfile = e.soundname || e.payload.sound;
  84.             // if the notification contains a soundname, play it.
  85.             var my_media = new Media("/android_asset/www/"+ soundfile);
  86.             my_media.play();
  87.         }
  88.         else
  89.         { // otherwise we were launched because the user touched a notification in the notification tray.
  90.             if ( e.coldstart )
  91.             {
  92.                 $("#app-status-ul").append('<li>--COLDSTART NOTIFICATION--' + '</li>');
  93.             }
  94.             else
  95.             {
  96.                 $("#app-status-ul").append('<li>--BACKGROUND NOTIFICATION--' + '</li>');
  97.             }
  98.         }
  99.      $("#app-status-ul").append('<li>MESSAGE -> MSG: ' + e.payload.message + '</li>');
  100.          //Only works for GCM
  101.      $("#app-status-ul").append('<li>MESSAGE -> MSGCNT: ' + e.payload.msgcnt + '</li>');
  102.      //Only works on Amazon Fire OS
  103.      $status.append('<li>MESSAGE -> TIME: ' + e.payload.timeStamp + '</li>');
  104.     break;
  105.     case 'error':
  106.         $("#app-status-ul").append('<li>ERROR -> MSG:' + e.msg + '</li>');
  107.     break;
  108.     default:
  109.         $("#app-status-ul").append('<li>EVENT -> Unknown, an event was received and we do not know what it is</li>');
  110.     break;
  111. }
  112. }
  113. // iOSの通知
  114. function onNotificationAPN (event) {
  115.     if ( event.alert )
  116.     {
  117.         navigator.notification.alert(event.alert);
  118.     }
  119.     if ( event.sound )
  120.     {
  121.         var snd = new Media(event.sound);
  122.         snd.play();
  123.     }
  124.     if ( event.badge )
  125.     {
  126.         pushNotification.setApplicationIconBadgeNumber(successHandler, errorHandler, event.badge);
  127.     }
  128. }
  129. </script>
  130. </body>
  131. </html>





ソースを眺めてわかったことは、Androidの場合、

1.SenderID(プロジェクト番号)を送信して、GCMサーバーからregidを得る。
これは端末ごとにユニークな値が割り振られる。

2.メッセージを送信する際は、API KEYとこのregidを指定して、端末にメッセージを送る。

という流れになることです。



実際のアプリケーションでは、端末側で取得したregidを自前のサーバーに送信。
保存しておいたregidを指定して、メッセージを送信するという処理になると思います。

今回はデバッグですので、とりあえず
Cordova デバッグ Androidエミュレーター実行時のconsole.logの見方

こちらで調べたやり方で、console.logに出力したregidを取得します。
※このキー、180文字近くあるので何かしらの方法でコピーする必要があります。


プログラムを作成したらエミュレーターを起動。


$ cordova emulate android



result = OKと表示された後しばらく待つと、registeredイベントが実行されます。


ログを確認して、redIDを取得します。


$ adb logcat CordovaLog:V *:S
...
D/CordovaLog( 3472): file:///android_asset/www/index.html: Line 77 :
regID = APA91bHbPGhwdQPcHcUYMp015Ge8V9Al4KX2mLNGAOxxxxxxxxxxxxxx...




これで通知を待ち受けている状態になりました。







GCMへデータの送信



GCMにデータを送信する画面があるんだろうと思っていたのですが、見つからない。
curlでデータを送信するサンプルをよく見かけるので、自前でpostしないと行けないようです。

面倒なので、Pythonのライブラリを使用することにしました。
https://github.com/geeknam/python-gcm

easy_installでインストールします。


$ sudo easy_install python-gcm




サンプルはこんな感じ。


  1. # -*- coding:utf-8 -*-
  2. from gcm import *
  3. gcm = GCM("AIzaSyDC3yeYa47F267GxWcMAmSRQxxxxx") # API KEYを指定
  4. data = {'the_message': 'You have x new friends', 'param2': 'value2'}
  5. # 端末から取得したregID(180文字ぐらい)を指定
  6. reg_id = 'APA91bGM_NhIrSGlUCITIXeTKyVMK4b73njxxxxxx...'
  7. # 送信実行
  8. gcm.plaintext_request(registration_id=reg_id, data=data)





プログラムを実行すると、こんな感じで通知を受け取ってくれると思います。


[広告 ] VPS





GCMから401エラーが帰ってくる場合



最初、GCMにメッセージを送ってもエラーになりハマりました。

いくつかパターンがあったのでメモしておきます。



gcm.gcm.GCMAuthenticationException: There was an error authenticating the sender account



このエラーが発生していたのは、APIの公開IPに「0.0.0.0/0」と
入力していた時でした。
許可IPを空白に変更し、全員許可にするとエラーは発生しなくなりました。




gcm.gcm.GCMInvalidRegistrationException: Registration ID is invalid



クライアントが受け取った180文字近いIDの指定が間違っている時に発生しました。





gcm.gcm.GCMMismatchSenderIdException: A Registration ID is tied to a certain group of senders



テスト時に別のアプリで作成したIDを誤って指定した場合に発生しました。



【参考URL】

https://github.com/phonegap-build/PushPlugin

GCMテスト用のAndroid Virtual Device (AVD) の準備

2. GCM アーキテクチャの概要

How To Create a Server to Send Push Notifications with GCM to Android Devices Using Python

https://github.com/geeknam/python-gcm

関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2015/03/01(日) 16:47:36|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<Cordova GCMからのプッシュ内容を通知領域に表示する | ホーム | Cordova アプリケーションのアイコンを変更する>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1661-7af1ec02
この記事にトラックバックする(FC2ブログユーザー)