Android Cloud to Device Messaging Framework を。


おもしろそうなので、まずはドキュメントをみる。

Google Projects for Android: C2DM


処理の流れは、

  1. Androidアプリを起動して受信登録する。
  2. 外部アプリ上でAndroidにメッセージを送信しようとボタンなどを押す。
  3. AndroidアプリがC2DMサーバからメッセージを受信する。

だと書いてる。
C2DMサーバを経由するようだ。

Enabling C2DM. An Android application running on a mobile device registers to receive messages.
Sending a message. A third-party application server sends messages to the device.
Receiving a message. An Android application receives a message from a C2DM server.

あと、なんかいろいろかいてるのだが、いきなりサンプルコードをみてみる。
AndroidManifest.xmlはまあ気に留めておくとして。

受信(Android)アプリ側

C2DM サーバに登録と登録削除
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0); // boilerplate
registrationIntent.putExtra("sender", emailOfSender);
startService(registrationIntent);
Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
startService(unregIntent);
C2DM サーバに登録削除後のレスポンス受信
public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
        handleRegistration(context, intent);
    } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
        handleMessage(context, intent);
     }
 }

private void handleRegistration(Context context, Intent intent) {
    String registration = intent.getStringExtra("registration_id"); 
    if (intent.getStringExtra("error") != null) {
        // Registration failed, should try again later.
    } else if (intent.getStringExtra("unregistered") != null) {
        // unregistration done, new messages from the authorized sender will be rejected
    } else if (registration != null) {
       // Send the registration ID to the 3rd party site that is sending the messages.
       // This should be done in a separate thread.
       // When done, remember that all registration is done. 
    }
}

メッセージを受信するには、受信可能状態であることをCD2Mサーバに教えておくことが必要。

CD2Mサーバからテキストを受信
protected void onReceive(Context context, Intent intent) {
    String accountName = intent.getExtras().getString(Config.C2DM_ACCOUNT_EXTRA);
    String message = intent.getExtras().getString(Config.C2DM_MESSAGE_EXTRA);
    if (Config.C2DM_MESSAGE_SYNC.equals(message)) {
        if (accountName != null) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Messaging request received for account " + accountName);
            }
            
            ContentResolver.requestSync(
                new Account(accountName, SyncAdapter.GOOGLE_ACCOUNT_TYPE),
                JumpNoteContract.AUTHORITY, new Bundle());
        }
    }
}


CD2Mサーバに登録成功すれば、あとはこのサーバにテキストを送信すればよし。と。
登録時のレスポンスと、CD2Mサーバからのテキスト受信は、同じレシーバで実装。

送信元アプリ側

WEBアプリでもその他のアプリでもPOSTだけでいいような雰囲気。

To send a message, the application server issues a POST request to https://android.apis.google.com/c2dm/send

で何をPOSTするのかというと、

  • registration_id
  • collapse_key
  • data.
  • delay_while_idle
  • Authorization: GoogleLogin auth=[AUTH_TOKEN]

リクエストヘッダを利用してトークンを渡す。
このAUTH_TOKENはGoogleのアカウントを利用して、GoogleClientLogintから取得する。

<?php
/**
 * CD2M client for 3rd-party application
 */
define('GOOGLE_CLIENTLOGIN_URL', 'https://www.google.com/accounts/ClientLogin');

// Google Client Login
$data = array('Email'   => 'youracount@gmail.com',
              'Passwd'  => 'password',
              'service' => 'ac2dm',
              'source'  => '');
$data = http_build_query($data, '', '&');

$header = array('Content-Type: application/x-www-form-urlencoded',
                'Content-Length: ' . strlen($data));

$context = array('http' => array(
                                 'method'  => 'POST',
                                 'header'  => implode("\r\n", $header),
                                 'content' => $data
                                 )
                 );

$response = file_get_contents(GOOGLE_CLIENTLOGIN_URL, false,
                              stream_context_create($context));
$lines = explode("\n", trim($response));

$registers = array();
foreach ($lines as $line) {
    list($key, $value) = explode('=', $line);
    $registers[$key] = $value;
}

var_dump($registers);
array(3) {
  ["SID"]=>
  string(224) "DQAxxJYAAAA1UafTri1HGxbjgMRPL2oZhK-eubtwF9pv29rbLQCq_cESmEaa5K4XkiF6RkK9ZRn5ICvvamX5xpIpwNLcEHUQH9k3vyNz_bnLatCJhSYoC8DajjyhQn7r0mhmokh-AwJXupNgzhyzvMJNCncuNge8eALBjQEJeaaWreGc3cqxZhmH3FFxWsoOo8uTFW0iWsRayUSK5Ty-P8gaglri_I3I1d"
  ["LSID"]=>
  string(224) "DQAxxJcAAABsIHpacQ8gtaqtacyb3kIiDS0WfTiK9ve_j2GFttanBr7z5QLnnUwrQz2M6S1pHFFnJLHJ5vAaapur3bTnAQgKEYKLSYGN-FCyMtadCpwZOc3FxkZ80atUGGh23UcaakLu6Q54nRtR5BE5tgh1t18tmCMjISnyZMEz6UTX_O-JZE7xO8UoSfyCaCRRQPshGY-IcfWYDIa1wIWgTUWLfK0gbo"
  ["Auth"]=>
  string(224) "DQAxxJgAAAAlNWweqwVdTRzmpnK6FMgMwI6S2b4wnCku6WpjcwOQNF64RVoxf0TGoWocY8knlaMwnyRwdaaf7ZLH5KSkSV5msveMHcjh6Ll_f3itDxoZVMC9jx7z793cQwBUvHuidGKTsVtTXwEm0_O9TBuhe6W4-8slH-hvWqhR1YRYh8TrzWr3PZ-2pZHL0YIi3e4QWYL2c4Q3Zjb_NJxrceDl_1wV"
}

また、shなコードがありました。

#!/bin/sh
# USAGE : get_auth_token.sh email password
curl https://www.google.com/accounts/ClientLogin \
    -d Email=$1 -d "Passwd=$2" -d accountType=GOOGLE \
    -d source=Google-cURL-Example -d service=ac2dm

ワンタイムなトークンの仕組みを利用するのはYoutubeAPIなどでも同じ。

Android側のアプリをつくる

こんな記事が。
http://androidforums.com/android-developers/116833-c2dm-android-2-2-emulator.html

I am currently playing around with C2DM service and I am wondering if it is possible to test device-side C2DM application on Android 2.2 emulator? My current problem is that when my application sends registration intent to C2DM server, Logcat says:
Unable to start service Intent { act=com.google.android.c2dm.intent.REGISTER (has extras) }: not found
The same happens when I try to run examples - JumpNote and Google Chrome to Phone Extension that were mentioned here. Any ideas?
Solved this issue myself. I have installed SDK Platform Android 2.2, but haven't noticed that for testing C2DM additionally Google APIs package is needed

C2DMのAPIパッケージってどこにあるのだろう。

C2DMは、2.2以上のAndroidが走っているデバイスが必要である。かつ、Android Marketアプリがインストールされていなければならない。
ユーザは、モバイル上で、Googleアカウントの設定をしておかなければならない。