Android GCM 受信したメッセージを表示

Android

Android GCM 受信したメッセージを表示

Android GCMでメッセージを送るが多くの方に見て頂いているようで、有難うございます。
なので、調子に乗って、GCMでメッセージをサーバーから受信するところも書いておこうと思います。

Android GCMでメッセージを送るとは違い、サーバーサイドはJsonを利用したスクリプトを用意します。
下記の通りです。(http://labs.distriqt.com/post/1273 さんのものを引用させて頂きました。)

 <?php
 
 $url = 'https://android.googleapis.com/gcm/send';
 
 $registrationId = 'APA91bHqwcC6ztIHr2TZcr2Fmp_eWcqS0EHn796Cd8NKWb32tTJLz***'; //registration IDはここ
 $apiKey="AIzaSyBYyErq****"; //API Keyはここ
  
 //送りたいメッセージ
 $message      = "the test message";
 $tickerText   = "ticker text message";
 $contentTitle = "content title";
 $contentText  = "content body";
 
 
 $response = sendNotification( 
                $apiKey, 
                array($registrationId), 
                array('message' => $message, 'tickerText' => $tickerText, 'contentTitle' => $contentTitle, 
                "contentText" => $contentText) );
 
 echo $response;
 
 function sendNotification( $apiKey, $registrationIdsArray, $messageData )
 {   
    $headers = array("Content-Type:" . "application/json", "Authorization:" . "key=" . $apiKey);
    $data = array(
        'data' => $messageData,
        'registration_ids' => $registrationIdsArray
    );
 
    $ch = curl_init();
 
    curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); 
    curl_setopt( $ch, CURLOPT_URL, "https://android.googleapis.com/gcm/send" );
    curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
    curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode($data) );
 
    $response = curl_exec($ch);
    curl_close($ch);
 
    return $response;
 } 
 ?>

最初はですね、data、でサーバーに送るのはいいんだけど、アプリ側で取得する時に、何かdataの中に決まった名前で入れなくていいの??と思ったんですが、dataの後は、自分で好きなようにデータの名前をつければいいんですね。

アプリ側は、
Android GCMでメッセージを送るでも利用した、Googleさんが用意してくれているデモアプリの com.google.android.gcm.demo.app を使います。

GCMIntentService.javaのonMessageを次のように変更します。

  protected void onMessage(Context context, Intent intent) {
        Log.i(TAG, "Received message");
        String message = getString(R.string.gcm_message);
        displayMessage(context, message);
        // notifies user
        generateNotification(context, message);
        
        //ここから後を追加        
        String tickerText = intent.getStringExtra("tickerText");
        
        Intent message_intent = new Intent(context, MessageReceivedActivity.class);
        message_intent.putExtra("tickerText", tickerText);
        message_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        startActivity(message_intent);
        
    }

メッセージを表示するアクティビティを用意します。
このあたりは、Android Cloud to Device Messaging (C2DM) – Tutorialを参考にさせて頂きました。

 //MessageReceivedActivity.javaを追加
 package com.google.android.gcm.demo.app;
  
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TextView;
 
 public class MessageReceivedActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_result);
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
    	
      String tickerText = extras.getString("tickerText");
      if (tickerText != null && tickerText.length() > 0) {
        TextView view = (TextView) findViewById(R.id.result);
        view.setText(tickerText);
      }
    }
 
    super.onCreate(savedInstanceState);
  }
 
 } 

レイアウトファイルです。

 //activity_result.xmlを追加
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" >
 
    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:text="No info."
        android:textAppearance="?android:attr/textAppearanceLarge" >
    </TextView>
 
 </LinearLayout> 

サーバーサイドのプログラムを実行すると、次の画面に切り替わり、tickerTextが受け取れたことがわかります。

gcm_message_received.png

Android GCM パラメーター、リミットについてなど

Android

Android GCM パラメーター、リミットについてなど

下記のAndroid developer公式サイトの要点を、まとめてみたので掲載しておきます。私が思うところの要点なので、抜けているところもあります。
http://developer.android.com/guide/google/gcm/adv.html

collapse_keyについて

collapse_key flagをONにしておくと、古いメッセージは廃棄されて、新しいメッセージにとって代わる
collapseなしでストアできる上限は100個
それ以上は廃棄される
collapse_keyについては、下のメッセージタイプにも関わる重要なパラメーター

GCMに端末が接続していない場合

GCMに端末が接続していない場合は、GCMに接続するまで待つ
delay_while_idle flag.をONにしてもしなくてもこれは同じ

たとえば工場出荷時に戻されるなどして、2度とGCMに接続されない場合、4週間は保存される

アプリケーションがインストールされていない端末に接続しようとした場合は、メッセージを廃棄して、registration IDを不正なものにする

スロットル

一度に大量のメッセージが送られないように、スロットルという仕組みがあり、大量にメッセージが送られた場合は、少し遅延時間が発生する

アプリのアップデートやリストア時

アプリケーションがアップデートされる場合は、registration IDが同一である保証はない
推奨されるのは、アプリケーションのバージョンを3rdパーティーのサーバーでも保存しておいて、バージョンが新しくなった場合はregistrationのプロセスをもう一度やらせるなどの対策が必要
同じく、バックアップやリストアで戻った場合、registration IDは違うものになる可能性あり

リトライについて

com.google.android.c2dm.intent.REGISTRATIONがエラーを受け取った場合は、だんだん時間間隔が長くなりながら、リトライする

GCMサーバーからの登録削除について

アプリのアンインストールでGCMサーバーからunregisterされる
ただ、これには多少の時間がかかる
なので、3rd partyでメッセージを送信した時に、NotRegisteredとなって帰ってくる場合もある

メッセージの送信できる上限

4096 bytesまでの送信が可能

“send-to-sync” (collapsible)型と
“message with payload” (non-collapsible message) 型のメッセージと2種類ある
Collapse key で切り替える

“send-to-sync”はたとえば、emailのアプリケーションで、25通メッセージを受け取ったら、25回メッセージは不要で、1回でいいのと同じ

“message with payload”はIMのようなメッセージ。
毎回違うメッセージを表示する、など
Collapse keyを省略すべし
GCMサーバーは100メッセージまでこの”message with payload”をためておける

“send-to-sync”の方が、バッテリーやパフォーマンスの点で軽いので、よろしい

メッセージの複数同時送信できる上限

同一のメッセージを、複数の宛先に送信することが可能。
1から1000まで。

メッセージの有効期限をつけられる

time_to_liveパラメータを利用
期限付きの招待状やチャットのお知らせなど、短い時間しかメッセージが必要でないなどの際に利用

0 to 2,419,200秒まで設定できる
たとえば、これを0に設定しておくと、フルスロットルでメッセージを送信してくれる
しかし、サーバーにはためてくれないので、送信できなかった場合はすぐ消えてしまう。

複数の送信者を設定できる

送信者は100まで。

Android GCMでメッセージを送る

Android GCM サーバーサイド

Android

Android GCM サーバーサイド

GCM(Google Cloud Messagingの略)サーバーサイトのプログラムですが、いつの間にかXMPPでもメッセージが送信できるようになっていたようです。

XMPPでメッセージが送信できるサーバーをCCS(Cloud Connection Server
)と呼んでいるようですね。

XMPPで送信する版と、HTTPでリクエストを投げるのと、違いを書いておきます。

GCMサーバー 

  1. クラウドから端末への一方的な通信のみ
  2. 非同期ではないので、次々とメッセージを送りたい時に、前のメッセージがブロックしてしまう
  3. HTTPでPOST
  4. 複数の送信先に対応

CCSサーバー 

  1. クラウドから端末、端末からクラウドへ両方へ非同期で通信できる
  2. XMPPで通信
  3. 通信に失敗した場合のエラーメッセージも、非同期ですぐ帰ってくる
  4. 複数の送信先に送信できない

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

サーバーサイドのスクリプトの書き方は、それぞれのやり方によって散らばっています。

GCMでのサーバーサイドスクリプト例

CCSでのサーバーサイドスクリプト例

Android GCM Reg IDが取得できない

Android

Android GCM Reg IDが取得できない

Android GCMでメッセージを送るでGCMの本当にさわりのGoogleさんのコードを紹介しましたが、ちょっとしたことでつまづきやすいので、書いておきます。。。

アクティビティでまずregIdを登録します。

 final String regId = GCMRegistrar.getRegistrationId(this);
    if (regId.equals("")) {
            // Automatically registers application on startup.
            GCMRegistrar.register(this, PlacesConstants.SENDER_ID);
        } else {
            // Device is already registered on GCM, check server.
            if (GCMRegistrar.isRegisteredOnServer(this)) {
                // Skips registration.
                tv.append(getString(R.string.already_registered) + "\n");
        }

しかし、いつまでもregIdが帰ってきません。
どうやらGCMIntentServiceが呼ばれていないようです…

ちなみに今日(2013/07/17)調べたところ、

 GCMRegistrar.getRegistrationId(this)

はDeprecatedされたようです…。
残念。GCM Registration IDの取得を見てみてください。

AndroidManifest.xmlを見直すと

  <receiver
            android:name="com.google.android.gcm.GCMBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
       <intent-filter>
           <!-- Receives the actual messages. -->
          <action android:name="com.google.android.c2dm.intent.RECEIVE" />
           <!-- Receives the registration id. -->
           <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="my.application" />
        </intent-filter>
  </receiver>

category android:name=”my.application”のmy.applicationの部分に、正しくアプリケーション名を書かなければいけなかったのですが、違う名前が入ってしまってました(^_^;

Android GCM

AndroidのGCMという機能はアプリに対してちょっとしたメッセージを送信できる機能です。
GCMはGoogle Cloud Messagingの略です。
お金はかかりません。

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

以前はC2DMというサービスでしたが、これがdeplicateされてGCMになりました。