本文译自:http://developer.android.com/training/cloudsync/gcm.html
谷歌的云消息(GCM)是一个用于给Android设备发送消息的免费服务。GCM能够极大的提高用户的体验。你的应用程序会保持最新的状态,而不用担心因唤醒无线信号所造成的电池电量的浪费,也不用使用轮询来询问服务器是否有更新。还有,GCM允许把一个单一的消息绑定到1000个接收端,这样你就可以在恰当的时机快速的联系到大量的用户,同时最大限度的减少了服务器的工作负载。
本文讨论一些把GCM集成到应用程序中的最佳实践,并且假设你已经熟悉了这个服务的基本实现,如果你还不熟悉,请阅读“GCM示例指南”
高效的发送组播消息
在GCM中最有用的功能之一是支持高达1000个接收端来接收单一消息。这种能力让它很容易的把重要的消息发送给整个用户群。例如,你需要把一个消息发送给1,000,000个用户,并且你的服务器能够每秒钟发送大约500个消息。如果把每个消息只发送给一个接收端,那么需要1,000,000/500=2,000秒,大约有半个小时。但是,如果把每个消息绑定到1,000个接收端,那么把一个消息发送给1,000,000个接收端所需要的总的时间是(1,000,000/1,000)/500 = 2秒。这对于时间敏感型数据是非常有用的,如自然灾害警报或体育成绩等,间隔30分钟才发送信息就没有意义了。
这个功能是很容易使用的。如果你使用用于Java的GCM的辅助类库,那么只需简单的给send或sendNoRetry方法提供一个注册ID的List集合,而不是一个单一的注册ID。
// This method name is completely fabricated, but you getthe idea.
List regIds = whoShouldISendThisTo(message);
// If you want the SDK to automatically retry a certain numberof times, use the
// standard send method.
MulticastResult result = sender.send(message, regIds, 5);
// Otherwise, use sendNoRetry.
MulticastResult result = sender.sendNoRetry(message, regIds);
对于那些实现GCM支持的Java以外的语言,要构建一个带有下列数据报头的HTTP POST请求:
Authorization: key=YOUR_API_KEY
Content-type: application/json
然后把相关参数编码到一个JSON对象中,其中的registratioin_ids键要列出所有的注册ID。在下例中,除了registration_ids之外的所有参数都是可选的,嵌套在data中的项目代表了用户定义的有效负载,它不是GCM定义的参数。这个HTTP POST消息会被发送到https://android.googleapis.com/gcm/send。
{ "collapse_key": "score_update",
"time_to_live": 108,
"delay_while_idle": true,
"data": {
"score": "4 x 8",
"time": "15:16.2342"
},
"registration_ids":["4", "8", "15", "16", "23", "42"]
}
对于完整的组播GCM消息的介绍,请看GCM指南中的发送消息章节。
可以被替换的折叠消息
为了刷新数据,GCM消息服务会经常性的告诉移动应用连接相关服务器。在GCM中,对于这种情况可以创建可折叠的消息(并且建议要这样做),就是用新的消息替换就的消息。例如体育成绩的更新。如果你把某项比赛的最新成绩发送给所有的用户,并且在15分钟后,该项比赛成绩被更新了,那么早先的那个消息就不再重要了。因此对于那些没有接收到第一条消息的用户,没有必要两条都发送,并在只有一条重要的消息时强制设备反应两次(并提醒用户)。
当你定义了一个折叠的键,并且对于同一用户有多个消息在GCM服务中排队时,只有该折叠键关联的最后的那个消息会被发送。对于像体育成绩这样的消息,这样就会节省设备不必要的工作,以及潜在的过度的通知用户。对于服务同步相关的操作(如检查邮件),这样做可减少大量的设备同步操作。例如,如果在服务器上有10封邮件,并且这个10封“新邮件”的通知已经发送给设备,那么设备只需同步一次邮件就可以了。
为了使用这个功能,只要给要发出的消息添加一个折叠键。如果你正在使用GCM辅助类库,请使用Message类的collapseKey(String key)方法。
Message message = new Message.Builder(regId)
.collapseKey("game4_scores") // The key for game4.
.ttl(600) // Time in seconds to keep message queued ifdevice offline.
.delayWhileIdle(true) // Wait for device to become active beforesending.
.addPayload("key1", "value1")
.addPayload("key2", "value2")
.build();
如果没有使用辅助类库,只需简单把带有collapse_key字段名的变量添加到你构造的POST头中,并且把该键所对应的字符串设置为要更新的值。
直接把数据嵌入到GCM消息中
通常,GCM消息就是一个简单的通知,或是指示设备在服务器上有新的数据等待刷新。但是,一个GCM消息可达4KB,因此有时可利用GCM消息自己来发送数据,这样设备就不必连接服务器了。在以下状态下可考虑使用这种方法:
总的数据量要限制在4KB以内;
每个消息都是重要的,并要予以保留;
没有必要把多个GCM消息折叠成一个单一的服务器上的新数据。
例如,短信或基于回合制网络游戏中游戏者移动的编码都是把数据直接嵌入到一个GCM消息中的很好的例子。把Email嵌入到GCM消息中不是一个好的用例,因为Email的消息经常会大于4KB,并且用户不需要为每个Email邮件来等待来自服务器上的GCM消息。
在发送组播消息时也可以考虑使用这种方法,这样就不必告诉你用户群中每个设备为了更新而同时访问你的服务器。
因为以下几个原因,这种策略不适合用于发送大数据:
1.用速率限制来防止恶意的或不良代码的应用程序向个人设备散发消息;
2.消息不保证是按顺序到达的;
3.即使设备以最大每秒1K的速率,或更大的速率来接收一个GCM消息,也不能保证消息发出后就能立即到达。
如果使用得当,直接把数据嵌入到GCM消息可以提升应用接收数据的速度,因为它跳过了对你的服务器的访问。
让GCM消息发挥智能化的作用
你的应用程序不应该只是接收GCM消息,而应该发挥智能化作用。如何发挥作用则要依赖其内容。
不要讨人嫌
当接收大提醒用户刷新数据的消息时,很容易跨越从“有用”到“烦人”的界限。如果你的应用程序使用的是状态栏通知,就要更新既存的通知,而不是创建一个新的通知。如果你使用蜂鸣声或振动来提醒用户,就要考虑建立一个计时器。每分钟的提醒不要多于一次,从而避免用户卸载你的应用程序,或关闭设备。
智能化的同步
当使用GCM来指示设备有新的数据需要从服务器中下载时,记住你有4KB的元数据,它可以帮助你的智能化的把数据发送给你的应用程序。例如,你有一个阅读资料的应用程序,并且你的用户有100份相关的资料,就可以使用GCM消息来帮助你的应用程序实现从服务器上智能化的下载数据。看下面的的实例,GCM消息是如何发挥作用的:
1. refresh---这是一种基本的方式,它会告诉你的应用程序下载每个相关的资料。你的应用程序既可以向100个不同的服务器请求发送资料请求,如果这些资料都集中在你的服务器上,也可以给你的服务器发送一个获取请求,每次更新,都会绑定并传输100份不同的资料。
2. refresh, feedID---这是一种比较好的方式,这样你的应用程序就会知道要更新指定的资料。
3. refresh, feedID, timestamp---这种方式最好。如果在GCM消息到达之前,用户进行了手动刷新,那么应用程序就可以比较时间戳,来确定是否需要做一些事情。