[置顶] Android服务器推送之GCM

GCM(Google Cloud Message for Android)是Google发布的Android服务器推送(push)技术。之前的C2DM(Android Cloud to Device Messaging)已与2012年6月26日被正式弃用,使用GCM,需要申请开通Google apis,Google apis包括了所有Google服务的api,比如Google Map、Google+、Analytics、YouTube等等,申请地址为: Google API 网站

GCM Architectural Overview

Google Cloud Messaging for Android (GCM)是一个能够帮助开发者从服务器端发送数据到运行在Android手机上的程序的服务。这个服务提供了一个简单,轻量级的机制使得服务器端可以告诉移动端的程序与服务器端建立直接的联系,来获取更新的程序或者用户的数据。C2DM服务可以处理所有的消息队列的问题并且可以把消息发送到目标机器上运行的目标程序。

简介

GCM的主要特点:

1  它允许第三方的程序服务端发送消息到他们的安卓设备。

2  GCM不能保证消息的发送和消息的顺序。

3  手机端的程序不需要一直运行来接收消息。系统会通过Intent  broadcast来唤醒程序当有新的消息到来时。当然程序需要设置适当的broadcast  receiverpermission

4  它不提供任何的用户界面或者其他的东西来处理消息。C2DM只是简单的把收到的原始消息传递给程序。这个程序提供了处理这个消息的方法。比如,这个程序可能抛出一个通知,显示一个自定义的界面或者只是同步数据。

5  GCM要求手机必须运行Android2.2或者更高版本并且要有Google Play Store 或者运行具有谷歌api 的Android 2.2虚拟机。但是,你不仅限于通过Google Play Store部署你的程序。

6  它使用一个现有的连接用于谷歌服务。对前置3.0设备,这要求用户在他们的移动设备设置他们的谷歌账户。Android 4.0.4或更高对于谷歌帐户是不要求的。

GCM如何工作?

这一节给你一个GCM如何工作的概况。

下面这张表总结了GCM里面关键的术语和概念。它们分成下面两类:

1. ComponentsGCM里面包含的组件

2. Credentials:用在不同阶段来确认各方都已经被认证的IDstokens。这样消息才能发到正确的地方。

Components

Mobile Device

运行着需要使用GCMandroid程序的手机. 这必须是一个2.2Android设备,安装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键包含在POSTheaer,发送消息。

生命周期流程

下面是C2DM的主要过程:

1. Enabling C2DM:运行在手机上注册了来接收消息的Android程序。

2. Sending a message:发送消息到手机的第三方程序服务器。

3. Receiving a message:从C2DM服务器接收消息的Android程序。

下面是上面3个步骤的详细描述。

Enabling GCM

下面是运行在手机上的Android程序注册接收消息的步骤:

1. 程序第一次要使用消息服务时,触发一个registration intentGCM服务器。这个registration intent(com.google.android.c2dm.intent.REGISTER)包括sender ID以及 安卓application ID

2. 如果注册成功,GCM服务器broadcasts一个com.google.android.c2dm.intent.REGISTRATION intent,它给予安卓程序registration ID

程序应该保存这个ID留待后用。google可能定期的刷新registration ID,所以你的com.google.android.c2dm.intent.REGISTRATION Intent必须可以多次调用。程序应该能够做出相应的反应。

3. 为了完成注册,程序要把registration ID发送给第三方服务器端。第三方程序服务器通常把这个ID存在数据库中。

Sending a Message

如果第三方程序服务器要发送消息,下面的事情必须就位:

1对某个特定的设备,这个程序有一个允许它接收消息的registration ID

2第三方程序服务器存储了这个registration ID

3一个API键。这个是开发者必须在第三方程序服务器上为程序设置的东西(更多信息,看这里 Role of the Third-Party Application Server) 现在它被用来发送消息到手机。

下面是第三方程序服务器发送消息的步骤:

1第三方程序服务器发送消息到GCM服务器。

2如果用户的手机当前不在线,google会把这个消息入队并存储这个消息。

3当用户手机在线时,google发送消息到手机。

4在手机端,系统使用适当的permission通过Intent broadcast把这个消息broadcast到特定的程序,然后特定的程序获得这个消息。这样就唤醒了这个程序。应用程序不需要提前运行来接收这个消息。

5程序处理这个消息。如果应用程序是做一个复杂的处理,你可能想获取屏幕唤醒锁并且在Service里做任何处理。   

Receiving a Message

手机上的程序收到消息时的步骤:

1系统收到消息,然后从消息中提取键值对。

2系统使用com.google.android.c2dm.intent.RECEIVE Intent把键值对传给目标程序。

3目标程序从RECEIVE Intent中根据key取得数据并处理数据。

Writing Android Application that use GCM

想要写一个使用GCM的程序,你必须有一个程序服务器端能够执行 Role of the Third-Party Application Server所描述的任务。这一节描述了你创建一个使用GCM客户端的步骤。

请记住GCM是没有用户界面的。怎么在程序里处理消息取决于你。

写个程序客户端有两个主要步骤:

1. 创建一个manifest文件。这个文件包含程序使用GCM需要使用的权限。

2. 写java代码。要使用GCM,程序要包括:

A. 开始和停止注册服务的代码。

B. Receivers for 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-否则安卓应用程序将不会得到消息。 

6 Receivers for com.google.android.c2dm.intent.RECEIVEcom.google.android.c2dm.intent.REGISTRATION.category设置成applicationPackage。服务需要com.google.android.c2dm.SEND权限,这样C2DM就可以发送消息给它。

请注意,这两个注册并且收到的消息的实现为意图。

7  一个意图服务来处理意图所收到的广播接收器。

8  如果GCM功能是至关重要的Android应用程序的功能,一定要设置Android:minSdkVersion =“8”在清单中。这确保了Android应用程序不是安装在一个环境中否则它不能正常运行。

这里摘录支持GCMmanifest

<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. appapplication’s ID.通过PendingIntent设置来允许registration service提取程序信息。

比如:

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。这些intentsGCM传过来表明一个设备被注册(或者没注册),或者传递消息。

处理这些意图可能需要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)

如果程序的要求(注册或者未注册)失败,错误将会以一个报错的代码发送过来,其他额外的将会被设置。这里是可能的error codes:

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 shared preferences

        // notify 3rd-party server about the registered ID

    }

        

    // unregistration succeeded

    if (unregistered != null) {

        // get old registration ID from shared preferences

        // notify 3rd-party server about the unregistered ID

    } 

        

    // last operation (registration or unregistration) returned an error;

    if (error != null) {

        if ("SERVICE_NOT_AVAILABLE".equals(error)) {

           // optionally retry using exponential back-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还包括一个从包含sender ID作为字符串的东西中调用的extra 

这里有个例子,再次使用了 MyIntentReceiver类

private void handleMessage(Intent intent) {

    // server sent 2 key-value pairs, score and time

    String score = intent.getExtra("score");

    String time = intent.getExtra("time");

    // generates a system notification to display 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。然后建模拟器的时候选择google api 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. 可以处理请求并可以按需要排列消息,例如使用exponential back-off.。

4. 可以存储API keyregistration IDs。API key包含在发送消息的Postheader里。

能够存储API键和客户端注册id。API键包含在头的POST请求,发送消息。

Sends Messages

这一节主要讲第三方程序服务器怎么发送消息到一个或者多个手机设备。

1第三方应用程序服务器可以发送消息到一个设备或多个设备。一个消息发送到多个设备同时被称为多播消息。

2你有两个选择在如何构建请求和响应:纯文本或JSON

3然而,发送组播消息,您必须使用JSON。纯文本将不会工作。

在第三方程序服务器发送消息到安卓程序之前,必须接受一个从它传来的注册ID

Request format

发送一个消息,应用程序服务器发出一个POST请求到https://android.googleapis.com/gcm/send。    

一个消息请求是由两部分组成HTTP header 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有额外的名字。例如,  "data":{"score":"3x1"}将会导致一个,名为score的额外intent,他的值是字符串3 x1。键/值对的数量不限,虽然有一个限制消息的总大小(4 kb)。注意该值必须被字符串封闭。如果你想要包括的物体或其他非字符串数据类型(如整数或布尔值),你不得不转换成字符串类型。还要注意的是key不应该是一个保留字(from或任意从google开始的单词)。可选的。

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>

负载数据,表示前缀的参数做数据,后缀作为键。例如,一个 data.score=3x1的参数将导致一个名为score的额外intent,它的值为字符串3x1。键/值对的数量不限,虽然限制消息的总大小(4 kb)。还要注意的是key不应该是一个保留字(from或任意从google开始的单词)。可选的。

delay_while_idle

应该为true呈现1或者truefalse用其他的方法。可选的,默认值是false

time_to_live

JAON相同(参看前一个表格)。可选的

如果你想要测试你的要求不用传送信息到设备(JSON或纯文本),您可以设置一个可选的值为真的名为dry_runHTTP参数,不需要参数来运行这个请求结果将是几乎完全相同的,除了消息不会被传给设备。因此,响应会包含消息的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),响应主体包含12行形式的键/值对。第一行总是可用的,它的内容是id=ID of sent message 或者Error=GCM error code.。第二行,如果可用,有格式registration_id=canonical ID

of registration_id=canonical ID第二行是可选的,只有当第一行没有错误的时候它可以被发送。我们建议用处理纯文本响应的方式处理JSON响应

一如果第一行开始于ID,检查第二行:

1如果第二行开始于registration_id,得到它的值在你的服务器数据库中替换注册IDs

二否则,得到error的值

1如果它是NotRegistered ,从你的服务器数据库移除你的注册ID

2否则,可能有一个不可恢复的错误。

注意:纯文本请求永远不会返回Unavailable 作为错误代码,他们将返回一个500 HTTP状态 

Interpreting an error response

这里是用于处理当试着发送信息到设备上时可能发生的不同类型的错误的建议:

Missing Registration ID

检查一个包含注册id的请求(无论是在纯文本消息中的gistration_id参数,或者在JSON中的registration_ids领域里)

错误代码是MissingRegistration时发生 。

Invalid Registration ID

检查你传到服务器的注册ID的格式。确保它匹配手机接收的在com.google.android.c2dm.intent.REGISTRATION意图里的注册ID以及确保你不是截断它或者增加额外的字符。

错误代码是InvalidRegistration时发生

Mismatched Sender

注册ID被绑定到特定的发送者组,当一个程序注册使用GCM时, 它必须允许指定发件人发送消息。确保你使用这些中的一个当你试着发送消息到设备时。如果你转换到了一个不同的发送者,这个存在的注册IDs将不工作。

当错误代码是 MismatchSenderId时发生

Unregistered Device

现有的注册ID在很多情况下可能不再是有效的,包括

1如果应用程序通过分配com.google.android.c2dm.intent.UNREGISTER意图手动注销

如果应用程序自动取消登记,这可以发生(但并不保证)如果用户卸载应用程序。

 如果注册ID到期,谷歌可能刷新注册IDs

对于所有这些情况下,您应该从第三方服务器删除此注册ID和停止使用它来发送消息。  错误代码是NotRegistered时发生。

Message Too Big

包含在一个消息中的负载数据的整个大小不能超过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" --header Content-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 being blacklisted. 
HTTP状态码为503的时候发生或者当结果数组的一个JSON对象的错误字段是Unavailable.

内部服务器错误

当尝试处理请求的时候服务器遇到了一个错误.你可以重新尝试相同的请求(服从超时部分列出来的要求),但是如果错误仍然存在,请向报告android-gcm组此问题.
Senders that cause problems risk being blacklisted. 
Happens when the HTTP status code is 500, or when the error field of a JSON object in the results array is InternalServerError.



GCM有以下特点:

  1. 可以使用第三方应用服务器向Android应用推送消息
  2. GCM不保证发送的消息的顺序,也不保证消息一定能够推送到手机(恩,谁也不能保证100%)
  3. Android应用不需要运行就可以接收消息(是的,你没有看错,因为gcm被集成到系统中了,目前一些第三方的推送是在后台运行一个service维持长连接,与这些第三方推送相比,GCM不额外的耗电)
  4. GCM只传递的数据(可以传递小于4kb的数据),对这些数据的处理可以全部由开发者控制(Google不对数据进行任何处理,仅仅转发一下而已)
  5. 对于Android4.04以上的系统使用GCM没有任何限制(国行手机也可以使用,截止2013年02月04日,android4.0+的份额为42.6%,随着4.0+版本的提升,Android的推送不再成为一个问题 Android版本分布),Android2.2以上的系统需要安装Google Play Store,Android2.2以下的系统不能够使用GCM
  6. 对于Android3.0以前的系统,需要在设备上设置google账号
  7. gcm一次最多只能向1000部设备发送消息,没有提供向所有用户发送的接口(可能google认为向应用程序推送的消息都是与该用户相关的,如果你非要实现群发,一次发送1000个用户,多发送几次就行了)

GCM使用流程如下图所示:

App是运行在Android手机上的应用程序,GCM Server是Google的GCM服务器,Our Server是第三方应用服务器。具体流程如下:

  1. App发送 SenderIDGCM Server注册接收推送信息(SendID是开发者在Google的网站开通GCM服务时,创建项目的项目号)。
  2. GCM Server 向App返回RegId(RegId是GCM服务器通过一定算法生产的,可以唯一确定某一部手机上的某一个应用,这个RegId很重要)。
  3. AppOur Server发送RegId(推送消息的时候要使用RegId,GCM服务器是使用RegId来确定某一部手机上的某一个应用接收消息的,所以第三方服务器需要保存它,需要注意的是RegId很长,比如可能有183位,存数据库时需要注意字段长度)
  4. Our ServerGCM Server发送消息,传递appkey和RegId(appkey分为Oauth api key和simple api key)
  5. GCM Server把消息推送给App

更多信息,请访问Android开发网站,上面有快速开发指导,客户端与服务端集成介绍,和Demo下载。

你可能感兴趣的:([置顶] Android服务器推送之GCM)