GCMArchitectural Overview
Google Cloud Messaging for Android (GCM)是一个能够帮助开发者从服务器端发送数据到运行在Android手机上的程序的服务。这个服务提供了一个简单,轻量级的机制使得服务器端可以告诉移动端的程序与服务器端建立直接的联系,来获取更新的程序或者用户的数据。C2DM服务可以处理所有的消息队列的问题并且可以把消息发送到目标机器上运行的目标程序。
简介
GCM的主要特点:
1 它允许第三方的程序服务端发送消息到他们的安卓设备。
2 GCM不能保证消息的发送和消息的顺序。
3 手机端的程序不需要一直运行来接收消息。系统会通过Intent broadcast来唤醒程序当有新的消息到来时。当然程序需要设置适当的broadcast receiver和permission。
4 它不提供任何的用户界面或者其他的东西来处理消息。C2DM只是简单的把收到的原始消息传递给程序。这个程序提供了处理这个消息的方法。比如,这个程序可能抛出一个通知,显示一个自定义的界面或者只是同步数据。
5 GCM要求手机必须运行Android2.2或者更高版本并且要有GooglePlay Store ,或者运行具有谷歌api 的Android 2.2虚拟机。但是,你不仅限于通过Google Play Store部署你的程序。
6 它使用一个现有的连接用于谷歌服务。对前置3.0设备,这要求用户在他们的移动设备设置他们的谷歌账户。Android 4.0.4或更高对于谷歌帐户是不要求的。
GCM如何工作?
下面这张表总结了GCM里面关键的术语和概念。它们分成下面两类:
1. Components:GCM里面包含的组件
2. Credentials:用在不同阶段来确认各方都已经被认证的IDs和tokens。这样消息才能发到正确的地方。
Components |
|
Mobile Device |
运行着需要使用GCM的android程序的手机. 这必须是一个2.2的Android设备,安装Google Play Store, 如果设备运行Android版本低于4.0.4它必须至少有一个登录谷歌账户。或者运行具有谷歌api 的Android 2.2虚拟机。 |
Third-Party Application Server |
一个应用程序服务器,开发人员设置实现GCM的一部分在他们的应用程序端。第三方程序服务端通过GCM服务器发送消息到运行Andoird程序的手机。 |
C2DM Servers |
Google服务器,从第三方程序服务器收消息并发到目标手机上的目标程序。 |
Credentials |
|
Sender ID |
你从api控制台获得project,如 Getting Started中描述的。Sender ID用在注册阶段去识别被允许发送消息到手机的android程序。 |
Application ID |
注册了用来接收消息的程序。 这个程序是通过manifest的包名来识别的。 这样确保消息会发送到正确的程序。 |
Registration ID |
这个ID是C2DM服务器分发的,用来允许程序接收消息。 当程序有了registration ID, 就把这个ID发送到第三方程序服务器, 第三方服务器用ID来识别每一个注册了来接收消息的手机。换句话说,registration ID是和运行在某个手机上的摸个程序绑定的。 |
Google User Account |
如果GCM要工作,手机就至少有一个已经登录的google账户,如果设备运行Android版本低于4.0.4 |
Sender Auth Token |
API key存储在第三方应用程序服务器,让应用服务器授权访问谷歌服务。API键包含在POST的heaer里,发送消息。 |
生命周期流程
下面是C2DM的主要过程:
1. Enabling C2DM:运行在手机上注册了来接收消息的Android程序。
2. Sending a message:发送消息到手机的第三方程序服务器。
3. Receiving a message:从C2DM服务器接收消息的Android程序。
下面是上面3个步骤的详细描述。
Enabling GCM
下面是运行在手机上的Android程序注册接收消息的步骤:
1. 程序第一次要使用消息服务时,触发一个registration intent到GCM服务器。这个registration intent(com.google.android.c2dm.intent.REGISTER)包括sender ID以及 安卓application ID。
2. 如果注册成功,GCM服务器broadcasts一个com.google.android.c2dm.intent.REGISTRATIONintent,它给予安卓程序registration ID。
程序应该保存这个ID留待后用。google可能定期的刷新registration ID,所以你的com.google.android.c2dm.intent.REGISTRATION Intent必须可以多次调用。程序应该能够做出相应的反应。
3. 为了完成注册,程序要把registrationID发送给第三方服务器端。第三方程序服务器通常把这个ID存在数据库中。
Sending a Message
1对某个特定的设备,这个程序有一个允许它接收消息的registration ID。
2第三方程序服务器存储了这个registrationID。
3一个API键。这个是开发者必须在第三方程序服务器上为程序设置的东西(更多信息,看这里 Role of the Third-PartyApplication Server) 现在它被用来发送消息到手机。
1第三方程序服务器发送消息到GCM服务器。
2如果用户的手机当前不在线,google会把这个消息入队并存储这个消息。
3当用户手机在线时,google发送消息到手机。
4在手机端,系统使用适当的permission通过Intent broadcast把这个消息broadcast到特定的程序,然后特定的程序获得这个消息。这样就唤醒了这个程序。应用程序不需要提前运行来接收这个消息。
5程序处理这个消息。如果应用程序是做一个复杂的处理,你可能想获取屏幕唤醒锁并且在Service里做任何处理。
Receiving a Message
手机上的程序收到消息时的步骤:
1系统收到消息,然后从消息中提取键值对。
2系统使用com.google.android.c2dm.intent.RECEIVEIntent把键值对传给目标程序。
3目标程序从RECEIVEIntent中根据key取得数据并处理数据。
Writing AndroidApplication that use GCM
想要写一个使用GCM的程序,你必须有一个程序服务器端能够执行 Role of theThird-Party Application Server所描述的任务。这一节描述了你创建一个使用GCM客户端的步骤。
请记住GCM是没有用户界面的。怎么在程序里处理消息取决于你。
写个程序客户端有两个主要步骤:
1. 创建一个manifest文件。这个文件包含程序使用GCM需要使用的权限。
2. 写java代码。要使用GCM,程序要包括:
A. 开始和停止注册服务的代码。
B. Receiversfor com.google.android.c2dm.intent.C2D_MESSAGE 和com.google.android.c2dm.intent.REGISTRATION。
Creating the Manifest
每一个程序在根目录下都有一个AndroidManifest.xml文件。这个文件提供程序的必要信息给Android系统,这些信息是系统在运行任何程序代码之前必须要有的。要使用GCM,这个文件必须包含:
1 com.google.android.c2dm.permission.RECEIVE。程序拥有注册和接受消息的权限。
2 android.permission.INTERNET。程序拥有联网的权限。
3 android.permission.GET_ACCOUNTS permission当GCM需要谷歌账户(但设备版本低于4.0.4时需要)
4 The android.permission.WAKE_LOCK permission程序可以保证处理器在睡觉的时候得到消息。
5 applicationPackage+”.permission.C2D_MESSAGE”防止其他程序注册和接受这个程序的消息。The permission name必须精确匹配这pattern-否则安卓应用程序将不会得到消息。
6Receivers for com.google.android.c2dm.intent.RECEIVE和com.google.android.c2dm.intent.REGISTRATION.category设置成applicationPackage。服务需要com.google.android.c2dm.SEND权限,这样C2DM就可以发送消息给它。
请注意,这两个注册并且收到的消息的实现为意图。
7 一个意图服务来处理意图所收到的广播接收器。
8 如果GCM功能是至关重要的Android应用程序的功能,一定要设置Android:minSdkVersion=“8”在清单中。这确保了Android应用程序不是安装在一个环境中否则它不能正常运行。
这里摘录支持GCM的manifest
<manifest package="com.example.gcm" ...>
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.example.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
<application ...>
<receiver
android:name=".MyBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.example.gcm" />
</intent-filter>
</receiver>
<service android:name=".MyIntentService" />
</application>
</manifest>
Registering for GCM
Android程序在接收任何消息前需要向GCM服务器注册。如果要注册,需要发送一个intent(com.google.android.c2dm.intent.REGISTER),包含2个参数:
1. sender:是一个授权发送消息到程序的ID,通常是程序开发者设置的一个gmail地址。
2. app:application’sID.通过PendingIntent设置来允许registrationservice提取程序信息。
比如:
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);
直到程序把registration ID发送到第三方程序服务器,注册才结束。第三方程序服务器使用这个registration ID发送消息给目标机器上的目标程序。
此意图将以异步方式发送到GCM服务器,响应将作为一个com.google.android.c2dm.intent.REGISTRATION意图被提交给应用程序,它包含分配到运行在那个特定的设备的Android应用程序的注册ID。
Unregistering from GCM
Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
startService(unregIntent);
类似于注册请求,此意图是异步发送的,响应是一个com.google.android.c2dm.intent.REGISTRATION意图。
Handling Intents sent by GCM
正如在 Creating the Manifest讨论的,manifest定义一个广播接收器为com.google.android.c2dm.intent.REGISTRATION
andcom.google.android.c2dm.intent.RECEIVE
intents。这些intents被GCM传过来表明一个设备被注册(或者没注册),或者传递消息。
处理这些意图可能需要I / O操作(如网络调用第三方服务器),这样的操作不应该在接收者的onReceive()方法里。你可能会直接产生一个新的线程,但没人能保证流程运行的足够长的时间来完成这项工作。因此建议的方式来处理意图就是给他们授权一个服务,比如一个IntentService。例如:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public final void onReceive(Context context, Intent intent) {
MyIntentService.runIntentInService(context, intent);
setResult(Activity.RESULT_OK, null, null);
}
}
然后在MyIntentService:
public class MyIntentService extends IntentService {
private static PowerManager.WakeLock sWakeLock;
private static final Object LOCK = MyIntentService.class;
static void runIntentInService(Context context, Intent intent) {
synchronized(LOCK) {
if (sWakeLock == null) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "my_wakelock");
}
}
sWakeLock.acquire();
intent.setClassName(context, MyIntentService.class.getName());
context.startService(intent);
}
@Override
public final void onHandleIntent(Intent intent) {
try {
String action = intent.getAction();
if (action.equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(intent);
} else if (action.equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(intent);
}
} finally {
synchronized(LOCK) {
sWakeLock.release();
}
}
}
}
注意:您的应用程序必须获得一个锁在开始服务签否则装置在服务启动前就进入待机状态了。
Handling Registration Results
当一个com.google.android.c2dm.intent.REGISTRATION意图被接受,它可能潜在的包含3个额外的东西:registration_id, error,and unregistered。
当注册成功, registration_id 包含注册ID和其他多余没有设置的东西。应用程序必须确保第三方服务器接收注册ID。它可以通过保存注册ID,并将其发送给服务器。如果网络中断了,或有错误,当网启动一次,或者在下次启动时,应用程序应该重新尝试发送注册ID。
注意:尽管com.google.android.c2dm.intent.REGISTRATION意图通常后收到的请求是由应用程序,谷歌可能会定期刷新注册ID。所以应用程序必须准备在任何时间好处理它。
当注销成功,只有额外未注册的被设置,以及类似的登记工作流程,应用程序必须联系第三方服务器删除注册ID(注意,注册ID在意图中是不可用的,但是应用程序得到注册ID时应该保存注册ID)。
如果程序的要求(注册或者未注册)失败,错误将会以一个报错的代码发送过来,其他额外的将会被设置。这里是可能的errorcodes:
Error Code |
Description |
SERVICE_NOT_AVAILABLE |
手机不能读取响应或者有500/503错误.程序应该使用指数退避然后重试。更多信息参见advanced topics |
ACCOUNT_MISSING |
手机上没有登录google账户. 程序应该要求用户打开账户控制并增加一个账户。 |
AUTHENTICATION_FAILED |
错误的密码,程序应该让用户输入正确的密码,并在稍后手动重试。 |
INVALID_SENDER |
Sender account不能被识别。这一定是固定在Android应用程序端。开发人员必须在com.google.android.c2dm.intent.REGISTER 意图里为应用程序提供正确的额外发送方 |
PHONE_REGISTRATION_ERROR |
手机和谷歌注册不正确。这个手机现在不支持GCM。 |
INVALID_PARAMETERS |
手机发送的请求没有包含预期的参数。这款手机目前不支持GCM。 |
这里的一个例子,说明如何处理在MyIntentService的注册:
private void handleRegistration(Intent intent) {
String registrationId = intent.getStringExtra("registration_id");
String error = intent.getStringExtra("error");
String unregistered = intent.getStringExtra("unregistered");
// registration succeeded
if (registrationId != null) {
// store registration ID on sharedpreferences
// notify 3rd-party server about theregistered ID
}
// unregistration succeeded
if (unregistered != null) {
// get old registration ID from sharedpreferences
// notify 3rd-party server about theunregistered ID
}
// last operation (registration or unregistration)returned an error;
if (error != null) {
if ("SERVICE_NOT_AVAILABLE".equals(error)) {
// optionally retry using exponentialback-off
// (see Advanced Topics)
} else {
// Unrecoverable error, log it
Log.i(TAG, "Received error: " + error);
}
}
}
com.google.android.c2dm.intent.RECEIVE
被GCM用来传送从第三方服务器
发送过来的信息到运行在手机上的程序的。如果服务器在数据参数中包含键值对,他们可以作为extra在意图中,用key作为额外的名称。GCM还包括一个从包含senderID作为字符串的东西中调用的extra。
这里有个例子,再次使用了 MyIntentReceiver类
private void handleMessage(Intent intent) {
// server sent 2 key-value pairs, score andtime
String score = intent.getExtra("score");
String time = intent.getExtra("time");
// generates a system notification todisplay the score and time
}
Developing and Testing Your Applications
下面是给开发和测试使用GCM的程序的一些建议:
1. 要开发和测试GCM程序。你需要在Android2.2的设备上运行和调试这个程序。这个设备包含基本的google服务。
2. 要在真机上面开发和调试,真机必须是Android2.2并且包含 Google Play Store。
3. 要在模拟器上开发和调试,需要通过 the Android SDK and AVD Manager下载Android2.2 Google APIs附加到你的SDK中,Android API 8。然后建模拟器的时候选择googleapi 8。具体来说,您需要下载的组件名为“Google APIs by Google Inc, Android API 8”。然后,你需要建立一个使用该系统的AVD。
4. 如果GCM对程序是一个至关重要的功能,必须在AndroidManifest.xml里设置android:minSdkVersion=”8”。确保程序装在能使程序正常运行的环境里。
Role of the Third-Party Application Server
在你写一个使用GCM的客户端程序之前,你必须有一个程序服务器并满足下面的要求:
。
1. 可以和客户端通信
2. 可以对GCM服务器发起HTTP请求
3. 可以处理请求并可以按需要排列消息,例如使用exponentialback-off.。
4. 可以存储API key和registration IDs。API key包含在发送消息的Post的header里。
能够存储API键和客户端注册id。API键包含在头的POST请求,发送消息。
这一节主要讲第三方程序服务器怎么发送消息到一个或者多个手机设备。
1第三方应用程序服务器可以发送消息到一个设备或多个设备。一个消息发送到多个设备同时被称为多播消息。
2你有两个选择在如何构建请求和响应:纯文本或JSON。
3然而,发送组播消息,您必须使用JSON。纯文本将不会工作。
在第三方程序服务器发送消息到安卓程序之前,必须接受一个从它传来的注册ID。
Request format
发送一个消息,应用程序服务器发出一个POST请求到https://android.googleapis.com/gcm/send。
一个消息请求是由两部分组成: HTTPheader and HTTP body。
HTTP header必须包含以下标题:
1 Authorization: key=YOUR_API_KEY
2Content-Type: application/json forJSON; application/x-www-form-urlencoded;
charset=UTF-8 for plain text.
例如
Content-Type:application/json
Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
{
"registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
"data" : {
...
},
}
注意:如果content - type被忽略,这种格式是假定为纯文本。
HTTP主体内容取决于你使用JSON或纯文本。为JSON,它必须包含一个字符串代表有以下领域的JSON对象:
Field |
Description |
registration_id |
必须参数。手机上的程序发过来的registration ID。 一个设备列表的字符串数组 (注册id),它接收消息。它必须包含至少1个和最多1000个的注册IDs。发送一个多播消息,您必须使用JSON。一个单一的消息发送到一个设备,您可以使用一个只有1个注册id的JSON对象或纯文本(见下文)。要求。 |
collapse_key |
必须参数。当手机离线的时候,一个任意的字符串用来处理一组消息,这样的话只有最后一条消息可以到客户端。 这是为了避免发送大量的消息到客户端当手机重新在线的时候。 不能保证消息的顺序,所以发送到客户端的消息不一定是第三方服务器发送的最后一条。查看 Advanced Topics,进一步讨论了这个话题。可选的,除非你使用的是time_to_live参数,在这样的情况下,您还必须指定一个collapse_key。 |
data |
一个JSON对象,该对象的字段代表消息的有效负载数据的键-值对。如果存在,它的有效负载数据将作为程序数据包含在意图中,同时key有额外的名字。例如, |
delay_while_idle |
如果包含,表明如果设备处于空闲状态消息不应该立即发送。服务器将等待设备在线,然后只有最后的消息对于每个collapse_key值将被发送。可选的。默认值是false,而且必须是一个JSON布尔。 |
time_to_live |
如果设备离线消息存储在GCM能保持多长时间(以秒计)。可选的(默认生存时间是4周,并必须设置为一个JSON数字)。如果你使用这个参数,您还必须指定一个collapse_key。 |
如果您使用的是纯文本替代JSON,消息字段必须设置为HTTP参数发送,并且它们的语法略有不同,描述如下:
Field |
Description |
registration_id |
必须参数。手机上的程序发过来的registration ID。 |
collapse_key |
和JSON相同(参照前一个表格)。可选参数 |
data.<key> |
负载数据,表示前缀的参数做数据,后缀作为键。例如,一个 |
delay_while_idle |
应该为true呈现1或者true,false用其他的方法。可选的,默认值是false |
time_to_live |
和JAON相同(参看前一个表格)。可选的 |
如果你想要测试你的要求不用传送信息到设备(JSON或纯文本),您可以设置一个可选的值为真的名为dry_run的HTTP参数,。不需要参数来运行这个请求结果将是几乎完全相同的,除了消息不会被传给设备。因此,响应会包含消息的fake IDs 和多播字段(参见响应格式)。
服务器响应:
Response |
Description |
200 |
消息已成功处理。响应主体将包含更多关于消息的状态的细节,但它的格式将取决于该请求是JSON还是纯文本。看Interpreting a success response 了解更多的细节。 |
400 |
只适用于JSON请求。表明请求无法为JSON格式的解析,或者它含有无效的字段(例如,需要数字的时候传递字符串)。确切的失效的原因在响应描述,请求重试之前,问题应该解决请求 |
401 |
验证发送方账户有错误。 |
500 |
当尝试处理请求的时候在GCM服务器有一个内部错误 |
503 |
表明服务器暂时不可连接. 发送者必须稍后重试, honoring any Retry-After header included in the response。应用程序服务器必须实现exponential back off。GCM服务器用了太长的时间处理请求。 |
Interpreting a success response
当一个JSON请求成功(HTTP状态代码200),响应主体包含一个有以下领域的JSON对象:
Field |
Description |
multicast_id |
唯一的ID(数字)识别多播消息 |
success |
处理的消息数量没有错误。 |
failure |
Number of messages that could not be processed.消息数量不能被处理 |
canonical_ids |
结果包含一个规范的registration ID See Advanced Topics for more discussion of this topic. |
results |
对象数组代表消息处理的地位。对象作为请求使用相同的顺序列出。 (例如,对于每个在请求里的注册ID,其结果在响应里用相同的结果列出),他们可以有这些领域: · message_id: 当消息被成功处理时字符串代表消息。 · registration_id:如果设置,那么意味着,GCM处理消息,但它还有另一个规范的注册ID对那个设备,因此,发送者在将来的请求中应该替换IDs (否则他们可能被拒绝)。这个字段是决不会被设置如果出现错误请求。 · error: · 字符串来描述一个处理接收者消息时发生的错误,。可能的值和上表显示的是一样的。再加上“不可用”(即服务器繁忙,GCM不能为特定的接收方处理消息。因此它可以重试)。 |
如果failure 和canonical_ids的值是0,就没有必要去解析剩余的响应。否则,我们建议您遍历结果字段和为列表中的对象做以下事情:
一如果消息id被设置,检查注册id:
1如果注册ID被设置, 在你的服务器数据库用新值替换原始ID (规范ID)。注意,原始ID不是结果的一部分,因此您需要从请求中传送的注册ID列表中获得它(使用相同的索引)。
二否则,得到error的值:
1如果它是Unavailable,你可以使用另一个请求重新发送它。
2如果它是NotRegistered,你应该把注册ID从服务器数据库移除,因为应用程序被设备重新安装了。
3否则,注册ID在请求中传输的时候有些错误。这可能是不可恢复的错误,也需要从服务器数据库删除注册。
See Interpreting an error response for all possible error values.
当一个纯文本请求成功(HTTP状态代码200),响应主体包含1或2行形式的键/值对。第一行总是可用的,它的内容是id=ID of sent message 或者Error=GCM error code.。第二行,如果可用,有格式registration_id=canonical ID
of registration_id=canonicalID。第二行是可选的,只有当第一行没有错误的时候它可以被发送。我们建议用处理纯文本响应的方式处理JSON响应:
一如果第一行开始于ID,检查第二行:
1如果第二行开始于registration_id,得到它的值在你的服务器数据库中替换注册IDs
二否则,得到error的值
1如果它是NotRegistered,从你的服务器数据库移除你的注册ID
2否则,可能有一个不可恢复的错误。
注意:纯文本请求永远不会返回Unavailable 作为错误代码,他们将返回一个500 HTTP状态
Interpreting an error response
这里是用于处理当试着发送信息到设备上时可能发生的不同类型的错误的建议:
MissingRegistration ID
检查一个包含注册id的请求(无论是在纯文本消息中的gistration_id参数,或者在JSON中的registration_ids领域里)
错误代码是MissingRegistration时发生 。
Invalid Registration ID
检查你传到服务器的注册ID的格式。确保它匹配手机接收的在com.google.android.c2dm.intent.REGISTRATION意图里的注册ID以及确保你不是截断它或者增加额外的字符。
错误代码是InvalidRegistration时发生
MismatchedSender
注册ID被绑定到特定的发送者组,当一个程序注册使用GCM时,它必须允许指定发件人发送消息。确保你使用这些中的一个当你试着发送消息到设备时。如果你转换到了一个不同的发送者,这个存在的注册IDs将不工作。
当错误代码是 MismatchSenderId时发生
UnregisteredDevice
现有的注册ID在很多情况下可能不再是有效的,包括
1如果应用程序通过分配com.google.android.c2dm.intent.UNREGISTER意图手动注销
2 如果应用程序自动取消登记,这可以发生(但并不保证)如果用户卸载应用程序。
3 如果注册ID到期,谷歌可能刷新注册IDs。
对于所有这些情况下,您应该从第三方服务器删除此注册ID和停止使用它来发送消息。 错误代码是NotRegistered时发生。
Message TooBig
包含在一个消息中的负载数据的整个大小不能超过4096字节,注意,这包括键和值的总大小。
错误代码是MessageTooBig时发生。
未注册的设备
现有的registeration ID在以下几种情况下可能失效:
· 如果应用程序通过发出一个意图(com.google.android.c2dm.intent.UNREGISTER)被手动注销.
· 如果应用程序被自动注销,这个有可能发生(但不能保证)是否用户卸载了应用程序.
· 如果 registeration ID过期,谷歌可能会决定刷新registeration IDs.
对于所有这些情况,你应该从第三方服务器删除registeration ID并且停
止使用它来发送信息.错误代码是NotRegistered的时候发生.
信息量太大
在消息中包含的有效载荷数据的总大小不能超过4096字节. 注意它包含键和值两者的大小.
当错误代码是MessageTooBig的时候发生.
存活的有效时间
存活的时间字段的值必须是一个从0到2419200秒(4周)的整数.错误代码为InvalidTtl的时候发生.
验证错误
你想使用的发送消息的发送人账户可能无法验证.可能的原因是:
· 验证信息的头部丢失或者是无效的语法.
· 作为key发送的无效的project ID.
· key有效但是GCM服务器禁用.
· 发送请求的服务器不在服务器Key IPs的白名单中.
检查你发送的验证信息头部里的标记是否和你的项目相联系的正确的APIkey.你可以通过以下命令来检查你的APIkey的有效性:
#api_key=YOUR_API_KEY
#curl --header "Authorization: key=$api_key" --headerContent-Type:"application/json" https://android.googleapis.com/gcm/send -d"{"registration_ids":["ABC"]}"
如果你收到一个401 HTTP状态代码,说明APIkey是无效的. 否则你会看到下面的一些信息:
{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
如果你想确认registeration ID的有效性,你可以用registeration ID来替换“ABC”.当HTTP状态码是401的时候发生.
超时
服务器无法及时处理请求.你应当重新尝试同样的请求,但是你必须遵守以下规定:
· 尊重重新尝试后的头部如果它包含在GCM服务器的回复中.
· 在你的重试机制中实施指数回退. 这意味着每一次重试之后有个指数增长的延时(例如. 你第一次重试时等待了1秒钟,下次至少等待2秒钟,然后是4秒钟,以此类推). 如果你发送多条信息,通过一个增加的随机量让每一个独立独立延时来避免在同一时间为所有的信息发送一个新的请求.
Senders that cause problems risk beingblacklisted.
当HTTP状态码为503的时候发生, 或者当结果数组的一个JSON对象的错误字段是Unavailable.
内部服务器错误
当尝试处理请求的时候服务器遇到了一个错误.你可以重新尝试相同的请求(服从超时部分列出来的要求),但是如果错误仍然存在,请向报告android-gcm组此问题.
Senders that cause problems risk being blacklisted.
Happens when the HTTP status code is 500, or when the errorfield of a JSON object in the results array isInternalServerError.