Google IO 2015で発表されたGCM (Google Cloud Messaging)の新機能

Google I/O 2015で発表されたGCM (Google Cloud Messaging)の新機能

Google I/O 2015 で発表された
Android でプッシュ通知を実現するためのGoogleが提供しているサービスGoogle Cloud Messagingについてまとめます。(※Chromeブラウザへのプッシュもできますが。)

# 新機能は iOS対応 と Topics の2つ

## 公式アナウンス

<!-- Place this tag in your head or just before your close body tag. -->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>

<!-- Place this tag where you want the widget to render. -->
<div class="g-post" data-href="https://plus.google.com/+AndroidDevelopers/posts/fiHeW4Y1hDf"></div>

## Google Developers のページも刷新されました

https://developers.google.com/cloud-messaging/

# 新機能について

# 新機能1「iOS 対応」

https://developers.google.com/cloud-messaging/ios/start
https://developers.google.com/cloud-messaging/ios/client

## 概要
* GCMを使ってiOSにPush通知を実現することが可能に。
* 実現方法としては裏でGCMがAPNsサーバ越しにPush通知をするため、GCM/APNs両方に登録が必要。

* Push通知の管理が一本化できるが、使えるオプションについてはまだ終えていない。 (追って調査)

# 新機能2「Topics」

出版/購読型モデルに基づく、PUSH通知の実現するための概念。
Topicsを用いることで、Push依頼を行う際に特定カテゴリに関して関心がある複数ユーザに対してまとめてPush通知を送信することを可能にする。
この機能を使うためには、GCMにPush依頼を行うサーバ側(app server)とアプリ側の改修が必要。

メリットとしては、アプリ利用者の特定セグメントに対してメッセージを内容を最適化したプッシュを実現する際にセグメント管理の仕組みが出来たこと。

従来までのGCMを用いたセグメントプッシュの実現方法としては、
app server側で対象のregistration tokenを抽出する必要があった。
具体的にapp serverにおけるセグメントプッシュを実現するための工程は下記のような流れになる

1. セグメントの定義 (セグメントの条件になる属性の定義、e.g. 性別、年齢、地域など)
2. アプリ から app server に registration token と共に属性情報を送信 (registration tokenとセグメント情報の管理)
3. 送信された属性情報を基に、registration token を抽出する
4. 抽出された registration token に対してPush依頼を実施

topicsの概念追加により、上記の2,3の工程にあたる
app serverでのデバイス情報の管理、セグメント毎のデバイス情報の抽出が不要になる。
今まで、セグメント別のプッシュ通知を独自で持っていない組織にとっては有用な機能ではないだろうか。

本来の使い方のイメージとしては、
Newsアプリにおいて、「芸能」、「政治」などに関する最新ニュース通知を受け取るという機能など
特定カテゴリに関する情報を購読するような形の機能実現のための利用が一番しっくり来るだろう。

https://developers.google.com/cloud-messaging/topic-messaging

# 関連の記事

* [Techcrunch:Google Cloud Messaging Adds Support For Topics And iOS Push Notifications](http://techcrunch.com/2015/05/28/google-cloud-messaging-adds-support-for-topics-and-ios-push-notifications/)

* [ZDNet Japan:グーグル、「Cloud Test Lab」を発表--「Cloud Messaging」はiOSに対応](http://japan.zdnet.com/article/35065190/)

----

# 以下 ドキュメント訳 (適当)

https://developers.google.com/cloud-messaging/topic-messaging

GCM topic messaging allows your app server to send a message to multiple devices that have opted in to a particular topic. 
Based on the publish/subscribe model, topic messaging supports up to one million subscriptions per app. 
The app server sends messages with payloads up to 2KB to the topic, and GCM handles the message routing and delivers the message reliably to the right devices. 
For example, users of a weather forecasting app could opt in to a "severe weather alerts" topic and receive notifications of storms threatening specified areas.


Developers can choose any topic name that matches the regular expression, "/topics/[a-zA-Z0-9-_.~%]+". You can configure when to subscribe, when to send messages, and how to handle the notification when it reaches the client app.


GCMトピックメッセージはあなたのアプリサーバから特定の話題を選択した複数デバイス(ユーザ)へのメッセージを送るため機能です。
[出版/購読型のモデル](http://ja.wikipedia.org/wiki/%E5%87%BA%E7%89%88-%E8%B3%BC%E8%AA%AD%E5%9E%8B%E3%83%A2%E3%83%87%E3%83%AB)に基づいて設計されています。1アプリに対して100万トピックまで登録が可能です。
アプリサーバはトピックに対してペイロード上限2KB までのメッセージを送信できます。
また、GCMはメッセージ経路、正しいデバイスに対して確実なメッセージ配信処理をハンドリングします。
例えば、天気予報のアプリのユーザが、天気警報トピックをユーザが選択していた場合、具体的な地域の嵐に関する通知を受け取ることができます。

開発者は正規表現 `/topics/[a-zA-Z0-9-_.~%]+`にマッチするトピックの名前を決めることができます。
あなたは登録される際に、いつメッセージを送信するのか？そして、どのように通知をクライアントアプリに届ける際の扱い方を決めることが可能です。


From the the server side, sending messages to a GCM topic is very similar to sending messages to an individual device or to a user group. The app server sets to with /topics/yourTopic. See Notifications and data messages for details on payload support. Examples in this page show how to send data messages to a topic in HTTP and XMPP protocols.


サーバ側からCGMトピックに対してメッセージ送信することは、ここのデバイスまたはグループユーザにメッセージを送リ方にとても似ています。
アプリサーバは トピックを`/topics/yourTopic`選択します。
通知とメッセージ情報のPayloadサポートの詳細を参照してください。
このページでの例はどのようにメッセージ情報をトピックに対して送るのか、HTTP or XMPP protocol毎の具体例を示します。

* HTTP POST Request
``` HTTP_POST_Request
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a GCM Topic Message!",
   }
}
```

* XMPP Message
``` XMPP_Message
<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to": "/topics/foo-bar",
      "message_id": "m-1366082849205" ,
      "data": {
          "message":"This is a GCM Topic Message!"
      }
  }
  </gcm>
</message>
```

Expect up to 30 seconds of delay before the GCM Connection Server returns a success or failure response to the topic send requests. Make sure to set the app server's timeout value in the request accordingly.

Refer to the Server Reference for all options available to send downstream messages to client app.

トピック送信リクエストのGCM接続サーバが成功/失敗のレスポンス返すまでの時間は30秒までに返却する仕様です。
アプリサーバのタイムアウト時間はリクエストこのリクエストに添って設定してください。

ダウンストリームメッセージをクライアントアプリへ送信するためのすべてのオプション、サーバリファレンスを参考にしてください。

https://developers.google.com/cloud-messaging/server-ref.html


Response format

With XMPP protocol, the response format for topic messages is identical to basic downstream messages. With HTTP, note that a success response specifies the message_id, while causes of failed messages are referenced in the error field:


XMPPプロトコルにおいてtopic メッセージのレスポンスフォーマットは基本的なダウンストリーミングメッセージが識別可能になっています。

HTTPプロトコルでは、成功時の具体的レスポンスは message_id 、一方失敗時のメッセージはエラーフィールドが参照可能になります。

```
//Success example:
{
  "message_id": "10"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}
```

## Receiving topic messages on an Android client app

To receive topic messages, each client app needs to obtain a registration token and subscribe to the topic using that token.

トピックメッセージを各クライアントアプリで受診するためにはregistration tokenが取得されていることと、指定するトークンが登録されている必要があります。

Obtain a registration token
First, include InstanceIDListenerService in the manifest:

まず、manifestにInstanceIdListenerServiceを定義してください。

```
<service android:name="[.MyInstanceIDService]" android:exported="false">
  <intent-filter>
         <action android:name="com.google.android.gms.iid.InstanceID"/>
  </intent-filter>
</service>
```

An Android application needs to register with GCM connection servers before it can receive messages. When an app registers, it receives a registration token and sends it to the app server. The client app should store a boolean value indicating whether the registration token has been sent to the server.

メッセージを受信する前にAndroidアプリがGCM接続サーバに登録するために必要です。
アプリ登録時に、registration token が伝達され、アプリサーバに取得したトークンをを送ります。

アプリはRegistration tokenをサーバに送ったかどうかBoolean値で保持しておくべきです。


Google provides the Instance ID API to handle the creation and updating of registration tokens. To obtain a token, call instanceID.getToken, providing the app server's sender ID and setting the scope to GoogleCloudMessaging.INSTANCE_ID_SCOPE. Do not call this method in the main thread; instead, use a service that extends IntentService as shown:


Google は
registration tokenの作成と更新を扱うInstance ID APIを提供しています。token取得するために instanceID.getTokenを呼び、アプリサーバのsender IDを提供し、GoogleCloudMessaging.INSTANCE_ID_SCOPE を設定します。このメッソッドはメインスレッドでは呼ばないでください。
IntentSeviceを拡張したサービスを利用して下記ように実装してください。

```
// Initially this call goes out to the network to retrieve the token, subsequent calls
// are local.
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
        GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.i(TAG, "GCM Registration Token: " + token);

// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);

// Subscribe to topic channels
subscribeTopics(token);

// You should store a boolean that indicates whether the generated token has been
// sent to your server. If the boolean is false, send the token to your server,
// otherwise your server should have already received the token.
sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, true).apply();
```

Once you've received your registration token, make sure to send it to your server as shown.

The listener service's onTokenRefresh method should be invoked if the GCM registration token has been refreshed:

一度、registration tokenを取得すると、registration token をあなたのサーバに送信できているか確かめてください。
もしGCM registration tokenをリフレッシュされた場合にListenerサービスのonTokenRefresh メソッドをinvokeすべきです。

```
@Override
public void onTokenRefresh() {
    // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
    Intent intent = new Intent(this, RegistrationIntentService.class);
    startService(intent);
}
```

Once onTokenRefresh is called, use InstanceID.getToken() to get a new registration token, and then send the new token to your app server.

See the Instance ID API reference for full detail on this API.

一度、onTokenRefresh が呼ばれると、InstanceId.getToken() が新しい registartion tokenを取得するために使用され、
新しいtokenをあなたのサーバに送信します。

※Note: GCM register() has been deprecated, and it is recommended to use InstanceID to perform general GCM registration management.
※ GCM register() は非推奨ですので、標準のGCM登録管理の実装として、InstanceId の利用を推奨します。

### Subscribe to a topic

To subscribe to a topic, the client app calls GCM PubSub subscribe() with the GCM registration token and topic name.

トピックを登録するために、クライアントアプリはregistration tokenとtopic名を指定して CGM pubSub subscribe() を呼びます。

```
GcmPubSub.getInstance(context).subscribe(regToken, "/topics/[yourTopic]", null);
```

To unsubscribe, the client app must call GCM PubSub unsubscribe() with the registration token and topic name.


登録解除するためには、クライアントアプリは GCM PubSub unsubscribe()をregistration tokenとtopic名を指定して呼ぶ必要があります。


### Receive and handle topic messages

Topic messages are delivered the same way as other GCM messages. The from field identifies if the message is a topic message and contains the specific topic name. For example: "from":"/topics/yourTopic".

The GCMReceiver and GCMListenerService services simplify message handling on Android client apps. See Implementing GCM Client on Android for more information.

Alternatively, developers who choose to not use the new GcmReceiver and GcmListenerService can implement their own GcmBroadcastReceiver to check for topic messages by looking at the from field.


トピックメッセージの受信方法と取り扱い方

topicメッセージは他のGCMメッセージと同様に配信されます。もし、そのメッセージがトピックメセージ場合、
`from` fieldが具体的なとトピック名を示します。
例えば、 `"from": "/topics/yourTopic"`のように。

GCMReceiver と GCM ListenerServices は Android client appsにおいてメッセージハンドリングを容易化します。
詳しい情報はGCM Client ANdroid を参照ください。

代替的に、新しい実装のGCMReceiver/GCMListenerServiceを選択しない開発者は
`from`フィールドを見ることでtopic messages の確認が GCMBroadcastReceiverでも可能です。