Google Cloud Messaging(GCM)简介与基本使用
官方文档参考:https://developers.google.com/cloud-messaging/gcm
GCM简介
Google Cloud Messaging (GCM)是Google提供的服务器与终端进行消息传递的轻量级解决方案,支持客户端与服务器的双向传递,可实现push下发、即时通讯等功能。
GCM使用HTTP或XMPP协议,两种协议支持的消息最大容量都是4kb(ios为2kb)
消息格式支持JSON或者TEXT(文本)
支持的终端有iOS、Android、Chrome
基本框架:
角色:
1. GCM Connection Servers:google服务,在AppServer与客户端之间进行消息中转处理
2. Client App:客户端
3. App Server:自实现的服务器, 实现HTTP或XMPP协议, 通过GCM将消息发送给客户端
基本工作方式:
1. 客户端注册, 获得registration tokens。
2. 发送下行(downstream)消息:
App Server发送一个下行消息GCM,如果客户端处于离线状态,则GCM将消息放入 队列。上线后再发出。客户端收到消息进行处理。
3. 发送上行(upstream)消息--只在使用XMPP协议时支持:
a) 客户端发送一个上行消息给XMPP连接服务器, 如果App server离线,则将消息放入队列,当App Server上线后再发送。
b) AppServer从XMPP连接服务器收取消息,并做以下事情
i. 分析消息头部(header)确认客户端发送的信息
ii. 发送“ack”给XMPP服务器,对其进行签收回应
iii. 对消息进行处理
GCM支持服务端的消息分发形式有
定向发送:服务器发送给指定的一个客户端
指定设备组(Device Groups)发送:服务器发送一个消息给一组指定客户端
Topic形式:客户端注册一个topic, GCM向这个topic发送消息, 所有注册了这个topic的客户端都会收到这个消息
Demo体验:
https://developers.google.com/cloud-messaging/android/start
可以按以上页面运行demo,对gcm有个直观感受
GCM服务端
一、GCM服务端包含两部分:
GCM Connection Servers:由Google提供,支持Http或XMPP(一般用来实现即时通讯)协议
App Server:由开发者实现,使用Http或XMPP与GCM Connection Servers通信,通过GCM提供的API对GCM Connection Servers进行调用
一般App Server需要提供以下能力:
A) 能够与客户端程序(client app)通信
B) 能够使用HTTP或XMPP协议向GCM Server发送消息
C) 能够使用Exponential Backoff处理request和response信息
D) 能够存储api key和客户端的token(不要将api key存储在客户端)
E) 如果使用XMPP,还要能够针对每个message生成一个唯一的id
二、两种协议:
HTTP:
1.只支持下行通信,即服务端发送消息给客户端。
2.同步性:App Server发送一个请求request,然后等待response返回,这个过程同步,在response没有返回之前整个过程是阻塞的。
3.JSON和文本消息都使用HTTP POST方法发送
XMPP:
1. 支持下行和上行通信,可以服务端向客户端发送消息,也可以客户端向服务端发送消息
2. 异步性:App Sever与客户端的交互过程是异步的,The XMPP connection server会异步地发送ack、json或者失败等消息
3. 不支持文本消息,JSON将被封装在XMPP消息体中
HTTP说明:
使用HTTP协议向GCM HTTP connection Server发送消息,必须通过POST方法。整个请求包含以下部分:
1. gcm地址
https://gcm-http.googleapis.com/gcm/send
2. 消息必须包含两部分:header和body
Header由Authorization和Content-Type组成
Authorization: key=YOUR_API_KEY
Content-Type: 指定消息体body的类型,如果使用json,则为application/json, 如果使用文本,则为application/x-www-form-urlencoded;charset=UTF-8。如果没有指定,则默认为文本
Body为消息内容,参数要符合GCM的api规范,api说明见HTTP Connection Server Reference
例如:
发送一个通知(notification)类型的消息
{ "notification": {
"title": "Portugal vs. Denmark",
"text": "5 to 1"
},
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
}
上面的to参数指定的是客户端的token,及发送给指定设备
发送一个data类型的消息:
{ "data": {
"score": "5x1",
"time": "15:10"
},
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
}
参数有必选和可选两种,像to参数就是必选的。
一个文本类型的消息是这样的:
collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.score=4x8&data.time=15:16.2342
下面模拟App Server,使用HTTP向GCM发送一个请求:
curl --header "Authorization: key=your_api_key" --header Content-Type:"application/json" https://gcm-http.googleapis.com/gcm/send -d "{\"notification\": {\"title\": \"Portugal vs Denmark\",\"text\": \"5 to 1\"},\"to\" : \"APA91bEcHbQrd3uGkAcZYV4iT8NsfCuMissVZRZ_OXAXZixbUIn7KhIWayjxkb02x4r7Dh4VU54Nvt1v7mAEV69rx6BTTE6oCBKVgN29Y8oVYc9RltV8mtxK77I5ivhs417Fwf4SVkxJ\"}"
XMPP说明:
参照以下教程
https://developers.google.com/cloud-messaging/ccs
三、三种消息分发方式:
To参数指定消息发送对象,有三种类型
1. 定向发送:
直接填写客户端token,如:
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
2. Topic广播:所有注册了指定topic的客户端都会收到,如:
"to" : "/topics/global"
这个值是自定义的, 需要客户端主动注册
3. 设备组:发送给一组设备,最大数量为20,一般用于一个用户用于多个设备的情况
用设备组,首先要获取要加入设备组的客户端的token,然后向GCM申请创建notification key, 所有设备共享同一个notification key
例如:
https://android.googleapis.com/gcm/notification
Content-Type:application/json
Authorization:key=API_KEY
project_id:SENDER_ID
{
"operation": "create",
"notification_key_name": "appUser-Chris",
"registration_ids": ["4", "8", "15", "16", "23", "42"]
}
创建成功后,可以发送消息:
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
"to": "aUniqueKey",
"data": {
"hello": "This is a GCM Device Group Message!",
}
}
GCM客户端实现(Android)
建议在Android Studio下开发, 本文as版本为1.4
环境要求:
1. 在2.3以上系统,并且装有Google Play Service
2. GCM直接使用Google Play Service的现有连接,3.0以前的系统需要使用帐号登录, 4.0.4以后不需要
实现步骤:
1. 创建一个新的应用
2. 获取配置文件
进入以下地址,创建一个应用,填写应用名与包名(与刚刚创建的应用一致),得到Server API Key和Sender ID
点击Generate configuration files, 下载配置文件
将加载的google-services.json文件放到android工程下的module根目录下,如app/
3. 在gradle中配置google play service
a) 在工程级的gradle的dependencies中加入classpath
b) 在module级的gradle的dependencies中加入:
注意,这里的版本要和你本地的android sdk内的gcm版本一致,gcm sdk在这里:
[AndroidSDK]\extras\google\m2repository\com\google\android\gms\play-services-gcm
c) 在module级的gradle中声明plugin
4. 编辑menifest
a) 声明一个<application-package-name> + ".permission.C2D_MESSAGE"格式的permission, 防止其他应用接受和发送你的消息,如
<permission android:name="com.joy.gcmtest.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.joy.gcmtest.permission.C2D_MESSAGE" />
这个permission的格式必须固定, 否则无效
b) 声明一个GcmReceiver, 用来处理GCM给应用发送的消息, 使用时需要声明一下权限
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
这个GcmReciever不需要自定义, 直接声明在menifest里即可
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example.gcm" />
</intent-filter>
</receiver>
c) 声明一个GcmListenerService, 并进行自定义实现,如下
<service
android:name="com.joy.gcmtest.MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
MyGcmListenerService是一个GcmListenerService的实现
这个Service用来处理从GCM收到的消息,当GCM发送过来消息, 会调用onMessageReceived方法, 这个方法中,data参数存储了消息内容
d) 声明一个InstanceIDListenerService的实例
<service
android:name="com.joy.gcmtest.MyInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
MyInstanceIDListenerService是InstanceIDListenerService的自定义实现,用来处理registration tokens的创建、更新等
e) 如果想在设备睡眠情况下, 收到消息时将其唤醒, 可添加android.permission.WAKE_LOCK权限
4. Java代码
a) 应用启动时, 首先检查googleplay是否可用
b) 注册token
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
getToken()的参数为senderId, 如果使用R.string.gcm_defaultSenderId,则是从本地的google-services.json文件里取出之前申请的senderId。
注册token后, 如果token发生变化, 会调用MyInstanceIDListenerService的onTokenRefresh()方法, 这时需要重新获取token
获得token后, 可以将此token发送给app server保存起来
每个android客户端应用的实例都有一个唯一的token,同一台机器重复卸载安装两次应用,他们的token是不一样的
c) 订阅topic
如果支持topic方式发送, 需要订阅topic
private void subscribeTopics(String token) throws IOException {
GcmPubSub pubSub = GcmPubSub.getInstance(this);
for (String topic : TOPICS) {
pubSub.subscribe(token, "/topics/" + topic, null);
}
}
d) 模拟App Server向GCM发送一个消息,GCM会将消息发送给客户端
$ curl --header "Authorization: key=your_api_key --header Content-Type:"application/json" https://gcm-http.googleapis.com/gcm/send -d "{\"to\":\"/topics/global\", \"data\":{\"message\":\"This is a Joy Custom GCM Topic TEST Message\"}}"
随后,GCM会调用客户端MyGcmListenerService的onMessageReceived方法,由此客户端就能收到消息了。
以上客户端代码可参考官方demo GitHub - googlesamples/google-services: A collection of quickstart samples demonstrating the Google APIs for Android and iOS