一.基础知识
当咱们开发须要和服务器交互的应用程序时,基本上都须要获取服务器端的数据,好比《地震及时通》就须要及时获取服务器上最新的地震信息。要获取服务器上不定时更新的信息通常来讲有两种方法,第一种是客户端使用Pull(拉)的方式,隔一段时间就去服务器上获取信息,看是否有更新的信息出现。第二种就是服务器使用Push(推送)的方式,当服务器端有新信息了,则把最新的信息Push到客户端上。 html
虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能,可是明显来讲Push is better than pull。由于Pull方式更费客户端的网络流量,更主要的是费电量。 java
Android从2.2版本开始增长了Cloud to Device Messaging(C2DM)框架,在系统中支持了Push功能,基于Android平台使用Push功能更加简单了。虽然C2DM目前还处在实验室阶段,不太小规模的使用应该没问题 android
下面咱们就来体验一下Android的C2DM功能。 chrome
二.C2DM框架
使用Android的C2DM功能有几个要求: express
1. 须要Android2.2及以上的系统版本。 apache
2. 使用C2DM功能的Android设备上须要设置好Google的帐户。 api
3. 须要在这里注册使用C2DM功能的用户邮箱帐号(最好为C2DM单独注册一个Gmail邮箱帐号)。 浏览器
咱们接下来C2DM的一个完整过程,这里借用一下Google官方推出的Chrome To Phone过程图来讲明下。 服务器
图1 C2DM操做过程图 网络
要使用C2DM来进行Push操做,基本上要使用如下6个步骤:
(1)注册:Android设备把使用C2DM功能的用户帐户(好比android.c2dm.demo@gmail.com)和App名称发送给C2DM服务器。
(2)C2DM服务器会返回一个registration_id值给Android设备,设备须要保存这个registration_id值。
(3)Android设备把得到的registration_id和C2DM功能的用户帐户(android.c2dm.demo@gmail.com)发送给本身的服务器,不过通常用户帐户信息由于和服务器肯定好的,因此没必要发送。
这样Android设备就完成了C2DM功能的注册过程,接下来就能够接收C2DM服务器Push过来的消息了。
(4)服务器得到数据。这里图中的例子Chrome To Phone,服务器接收到Chrome浏览器发送的数据。数据也能够是服务器本地产生的。这里的服务器是Google AppEngine(很好的一项服务,惋惜在国内被屏了),要换成本身的服务器。服务器还要获取注册使用C2DM功能的用户帐户(android.c2dm.demo@gmail.com)的ClientLogin权限Auth。
(5)服务器把要发送的数据和registration_id一块儿,而且头部带上获取的Auth,使用POST的方式发送给C2DM服务器。
(6)C2DM服务器会以Push的方式把数据发送给对应的Android设备,Android设备只要在程序中按以前和服务器商量好的格式从对应的key中获取数据便可。
这样咱们就大概明白了C2DM的工做流程,下面咱们就结合一个实例来具体的说明以上6个步骤。
三.实例开发
咱们要建立的程序名称为AndroidC2DMDemo,包名为com.ichliebephone.c2dm。
开始以前咱们先去C2DM网页上注册一下使用C2DM功能的用户帐户。
图2 应用程序名
其中应用程序名要填写带包名的完整名称,好比这里为om.ichliebephone.c2dm. AndroidC2DMDemo。
图3 C2DM用户帐户注册
这里的contact邮箱使用一个你能接收到邮件的邮箱便可,下面的Role(sender)account邮箱最好单独注册一个Gmail邮箱来使用C2DM服务。咱们这里使用的是专门注册的android.c2dm.deno@gmail.com 邮箱。
提交后,过一段时间就会收到Google发送过来的确认邮件,而后你就可使用C2DM的Push服务了。
介绍了这么多,咱们先来快速完成一个实例,只完成Android设备端的注册部分,不包含向服务器发送registration_id和服务器向C2DM服务器发送数据的具体代码,这部分只是用Ubuntu下的curl命令来模拟,主要是快速亲自体验一下Push的结果。
建立一个Android工程AndroidC2DMDemo,而且包含进Google的开源例子Chrome To Phone中的c2dm包com.google.android.c2dm,包中包含三个Java类,分别为:
第一个类为C2DMBaseReceiver:
- /*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package com.google.android.c2dm;
-
- import java.io.IOException;
-
- import android.app.AlarmManager;
- import android.app.IntentService;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.os.PowerManager;
- import android.util.Log;
-
- /**
- * Base class for C2D message receiver. Includes constants for the
- * strings used in the protocol.
- */
- /**
- * 接收和处理C2DM消息的基类
- * */
- public abstract class C2DMBaseReceiver extends IntentService {
- //和C2DM Push的Intent内容相关
- //从新向C2DM服务器注册
- private static final String C2DM_RETRY = "com.google.android.c2dm.intent.RETRY";
- //向C2DM服务器注册后的回调处理
- public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
- //接收到C2DM服务器的推送消息
- private static final String C2DM_INTENT = "com.google.android.c2dm.intent.RECEIVE";
-
- // Logging tag
- private static final String TAG = "C2DM";
-
- // Extras in the registration callback intents.
- //向C2DM注册返回的intent中包含的key
- public static final String EXTRA_UNREGISTERED = "unregistered";
- public static final String EXTRA_ERROR = "error";
- public static final String EXTRA_REGISTRATION_ID = "registration_id";
- //向C2DM注册出错的缘由
- public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
- public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
- public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
- public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
- public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
- public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
- public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
-
- // wakelock
- private static final String WAKELOCK_KEY = "C2DM_LIB";
-
- private static PowerManager.WakeLock mWakeLock;
- private final String senderId;
-
- /**
- * The C2DMReceiver class must create a no-arg constructor and pass the
- * sender id to be used for registration.
- */
- public C2DMBaseReceiver(String senderId) {
- // senderId is used as base name for threads, etc.
- super(senderId);
- this.senderId = senderId;
- }
- //下面几个是接收到C2DM Push过来的信息后的回调函数,均可以在继承的子类中处理
- /**
- * Called when a cloud message has been received.
- */
- /**
- * 接收到C2DM服务器Push的消息后的回调函数,须要在继承的子类中处理
- * */
- protected abstract void onMessage(Context context, Intent intent);
-
- /**
- * Called on registration error. Override to provide better
- * error messages.
- *
- * This is called in the context of a Service - no dialog or UI.
- */
- /**
- * 出错的回调函数
- * */
- public abstract void onError(Context context, String errorId);
-
- /**
- * Called when a registration token has been received.
- */
- /**
- * 注册后的回调函数
- * */
- public void onRegistered(Context context, String registrationId) throws IOException {
- // registrationId will also be saved
- }
-
- /**
- * Called when the device has been unregistered.
- */
- /**
- * 取消注册的回调函数
- * */
- public void onUnregistered(Context context) {
- }
-
- //IntentService的方法
- @Override
- public final void onHandleIntent(Intent intent) {
- try {
- Context context = getApplicationContext();
- if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
- handleRegistration(context, intent);//处理注册后的回调
- } else if (intent.getAction().equals(C2DM_INTENT)) {
- onMessage(context, intent);//处理C2DM Push消息的回调
- } else if (intent.getAction().equals(C2DM_RETRY)) {
- C2DMessaging.register(context, senderId); //从新注册
- }
- } finally {
- // Release the power lock, so phone can get back to sleep.
- // The lock is reference counted by default, so multiple
- // messages are ok.
-
- // If the onMessage() needs to spawn a thread or do something else,
- // it should use it's own lock.
- mWakeLock.release();
- }
- }
-
-
- /**
- * Called from the broadcast receiver.
- * Will process the received intent, call handleMessage(), registered(), etc.
- * in background threads, with a wake lock, while keeping the service
- * alive.
- */
- static void runIntentInService(Context context, Intent intent) {
- if (mWakeLock == null) {
- // This is called from BroadcastReceiver, there is no init.
- PowerManager pm =
- (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- WAKELOCK_KEY);
- }
- mWakeLock.acquire();
-
- // Use a naming convention, similar with how permissions and intents are
- // used. Alternatives are introspection or an ugly use of statics.
- String receiver = context.getPackageName() + ".C2DMReceiver";
- intent.setClassName(context, receiver);
-
- context.startService(intent);
-
- }
-
- //处理注册后的回调
- private void handleRegistration(final Context context, Intent intent) {
- final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
- String error = intent.getStringExtra(EXTRA_ERROR);
- String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
- Log.v(TAG, "handleRegistration");
- //打印出接收到的registraton_id
- Log.v(TAG, "dmControl: registrationId = " + registrationId +
- ", error = " + error + ", removed = " + removed);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "dmControl: registrationId = " + registrationId +
- ", error = " + error + ", removed = " + removed);
- }
- if (removed != null) {
- // Remember we are unregistered
- C2DMessaging.clearRegistrationId(context);
- onUnregistered(context);
- return;
- } else if (error != null) {
- // we are not registered, can try again
- C2DMessaging.clearRegistrationId(context);
- // Registration failed
- Log.e(TAG, "Registration error " + error);
- onError(context, error);
- if ("SERVICE_NOT_AVAILABLE".equals(error)) {
- long backoffTimeMs = C2DMessaging.getBackoff(context);
-
- Log.d(TAG, "Scheduling registration retry, backoff = " + backoffTimeMs);
- Intent retryIntent = new Intent(C2DM_RETRY);
- PendingIntent retryPIntent = PendingIntent.getBroadcast(context,
- 0 /*requestCode*/, retryIntent, 0 /*flags*/);
-
- AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- am.set(AlarmManager.ELAPSED_REALTIME,
- backoffTimeMs, retryPIntent);
-
- // Next retry should wait longer.
- backoffTimeMs *= 2;
- C2DMessaging.setBackoff(context, backoffTimeMs);
- }
- } else {
- try {
- onRegistered(context, registrationId);
- C2DMessaging.setRegistrationId(context, registrationId);
- } catch (IOException ex) {
- Log.e(TAG, "Registration error " + ex.getMessage());
- }
- }
- }
- }
第二个类为C2DMBroadcastReceiver:
- /*
- */
- package com.google.android.c2dm;
-
- import android.app.Activity;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
-
- /**
- * Helper class to handle BroadcastReciver behavior.
- * - can only run for a limited amount of time - it must start a real service
- * for longer activity
- * - must get the power lock, must make sure it's released when all done.
- *
- */
- /**
- * 帮助类,帮忙处理BroadcastReciver过程
- * */
- public class C2DMBroadcastReceiver extends BroadcastReceiver {
-
- @Override
- public final void onReceive(Context context, Intent intent) {
- // To keep things in one place.
- C2DMBaseReceiver.runIntentInService(context, intent);
- setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
- }
- }
第三个类为C2DMessaging:
- /*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package com.google.android.c2dm;
-
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.content.SharedPreferences;
- import android.content.SharedPreferences.Editor;
-
- /**
- * Utilities for device registration.
- *
- * Will keep track of the registration token in a private preference.
- */
- /**
- * 和注册相关的一些实用函数
- * */
- public class C2DMessaging {
- public static final String EXTRA_SENDER = "sender";
- public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
- public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
- public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
- public static final String LAST_REGISTRATION_CHANGE = "last_registration_change";
- public static final String BACKOFF = "backoff";
- public static final String GSF_PACKAGE = "com.google.android.gsf"; //GSF为GoogleServicesFramework.apk的缩写
-
-
- // package
- static final String PREFERENCE = "com.google.android.c2dm";
-
- private static final long DEFAULT_BACKOFF = 30000;
-
- /**
- * Initiate c2d messaging registration for the current application
- */
- public static void register(Context context,
- String senderId) {
- Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
- registrationIntent.setPackage(GSF_PACKAGE);
- registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
- PendingIntent.getBroadcast(context, 0, new Intent(), 0));
- registrationIntent.putExtra(EXTRA_SENDER, senderId);
- context.startService(registrationIntent);
- // TODO: if intent not found, notification on need to have GSF
- }
-
- /**
- * Unregister the application. New messages will be blocked by server.
- */
- public static void unregister(Context context) {
- Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
- regIntent.setPackage(GSF_PACKAGE);
- regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context,
- 0, new Intent(), 0));
- context.startService(regIntent);
- }
-
- /**
- * Return the current registration id.
- *
- * If result is empty, the registration has failed.
- *
- * @return registration id, or empty string if the registration is not complete.
- */
- public static String getRegistrationId(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- String registrationId = prefs.getString("dm_registration", "");
- return registrationId;
- }
-
- public static long getLastRegistrationChange(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- return prefs.getLong(LAST_REGISTRATION_CHANGE, 0);
- }
-
- static long getBackoff(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- return prefs.getLong(BACKOFF, DEFAULT_BACKOFF);
- }
-
- static void setBackoff(Context context, long backoff) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putLong(BACKOFF, backoff);
- editor.commit();
-
- }
-
- // package
- static void clearRegistrationId(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putString("dm_registration", "");
- editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis());
- editor.commit();
-
- }
-
- // package
- static void setRegistrationId(Context context, String registrationId) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putString("dm_registration", registrationId);
- editor.commit();
-
- }
- }
代码中已添加了部分中文注释,能够先大概了解下,等整个工程创建完了在一块儿解释。
而后建立咱们本身的包com.ichliebephone.c2dm,包含两个类,一个是工程的入口AndroidC2DMDemo:
- package com.ichliebephone.c2dm;
-
- import com.google.android.c2dm.C2DMessaging;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
-
- public class AndroidC2DMDemo extends Activity {
- /** Called when the activity is first created. */
- private static final String TAG = "AndroidC2DMDemo";
- public static final String SENDER_ID = "android.c2dm.demo@gmail.com"; //使用C2DM服务的用户帐户
- public static final String MESSAGE_KEY_ONE = "msg"; //和服务器商量好的接收消息的键值key
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- Log.v(TAG, "Start");
- //向C2DM服务器注册
- C2DMessaging.register(this, SENDER_ID);
- }
-
-
- }
很简单,就是开始向C2DM服务器进行注册。
另外一个类为C2DMBaseReceiver的子类C2DMReceiver:
- package com.ichliebephone.c2dm;
-
- import java.io.IOException;
-
- import android.app.Notification;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
-
- import com.google.android.c2dm.C2DMBaseReceiver;
- //接收C2DM服务器Push的消息,包括注册返回的registration_id消息,推送的数据消息等
- public class C2DMReceiver extends C2DMBaseReceiver{
-
- private static final String TAG="C2DMReceiver";
- //
- public C2DMReceiver()
- {
- super(AndroidC2DMDemo.SENDER_ID);
- }
- public C2DMReceiver(String senderId) {
- super(senderId);
- // TODO Auto-generated constructor stub
- }
- //接收到Push消息的回调函数
- @Override
- protected void onMessage(Context context, Intent intent) {
- // TODO Auto-generated method stub
- Log.v(TAG, "C2DMReceiver message");
- Bundle extras = intent.getExtras();
- if(extras!=null){
- String msg = (String)extras.get(AndroidC2DMDemo.MESSAGE_KEY_ONE);
- Log.v(TAG, "The received msg = "+msg);
- //在标题栏上显示通知
- NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- Notification notification = new Notification(R.drawable.icon, msg, System.currentTimeMillis());
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AndroidC2DMDemo.class), 0);
- notification.setLatestEventInfo(this, getString(R.string.app_name), msg, contentIntent);
- notificationManager.notify(0, notification);
-
- }
- }
-
- @Override
- public void onError(Context context, String errorId) {
- // TODO Auto-generated method stub
- Log.v(TAG, "C2DMReceiver error");
- }
-
- @Override
- public void onRegistered(Context context, String registrationId)
- throws IOException {
- // TODO Auto-generated method stub
- super.onRegistered(context, registrationId);
- Log.v(TAG, "C2DMReceiver Register");
- }
- @Override
- public void onUnregistered(Context context) {
- // TODO Auto-generated method stub
- super.onUnregistered(context);
- Log.v(TAG, "C2DMReceiver UnRegister");
- }
- }
在这个类中咱们主要在接收到Push的回调函数onMessage中对消息进行了接收,而且使用Notification的方式显示在状态栏上。
咱们完整的工程目录是这样的:
图4 工程目录
最后咱们还要在AndroidManifest.xml中增长对应的权限等内容:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.ichliebephone.c2dm"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-sdk android:minSdkVersion="8" />
-
- <!--Only this application can receive the message and registration result -->
- <!-- 设置一个权限,使只有这个应用才能接收到对应Push的消息及注册时返回的结果 -->
- <permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"
- android:protectionLevel="signature"></permission>
- <uses-permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"/>
- <!-- This application has the permission to register and receive c2dm message -->
- <!-- 设置注册和接收C2DM Push消息的权限 -->
- <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
- <!-- Send and registration id to the server -->
- <!-- 设置联网权限,在把registration_id发送给服务器的时候要用 -->
- <uses-permission android:name="android.permission.INTERNET" />
- <!-- App must have this permission to use the library -->
- <!-- 其余和获取手机中用户帐户相关的权限 -->
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
- <uses-permission android:name="android.permission.USE_CREDENTIALS" />
-
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name=".AndroidC2DMDemo"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- <!-- In order to use the c2dm library, an
- application must declare a class with the name C2DMReceiver, in its
- own package, extending com.google.android.c2dm.C2DMBaseReceiver
- It must also include this section in the manifest. -->
- <!-- 为了使用c2dm包com.google.android.c2dm及其对应的3个类,咱们须要声明一个
- 继承com.google.android.c2dm.C2DMBaseReceiver类的子类C2DMReceiver,
- 而且要在这声明下 -->
- <service android:name=".C2DMReceiver" />
-
- <!-- Only google service can send data messages for the app. If permission is not set -
- any other app can generate it -->
- <!-- 谷歌的C2DM服务只为这个程序发送数据,声明对应的权限 -->
- <receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
- android:permission="com.google.android.c2dm.permission.SEND">
- <!-- Receive the actual message -->
- <!-- 能够接收实际的Push数据 -->
- <intent-filter>
- <action android:name="com.google.android.c2dm.intent.RECEIVE" />
- <category android:name="com.ichliebephone.c2dm" />
- </intent-filter>
- <!-- Receive the registration id -->
- <!-- 能够接收注册后返回的registration_id -->
- <intent-filter>
- <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
- <category android:name="com.ichliebephone.c2dm" />
- </intent-filter>
- </receiver>
- </application>
- </manifest>
由于C2DM功能只有2.2及以上的Android系统才支持,所以建立一个2.2及以上的AVD,而后在”设置->帐户与同步”里还要设置好Google Account,以下图所示:
图5 设置Android设备中的Google帐户
而后就能够运行程序了,咱们会在DDMS输出中看到得到的registration_id:
图6 得到的registration_id
若是第一次运行没有出现,试着再运行一次。
有了registration_id,咱们的服务器端就能够向C2DM端发送须要Push的数据了,这里进行简单化处理下,在Ubuntu下直接使用curl命令来模拟服务器功能向C2DM发送数据。
咱们先来获取C2DM的ClientLogin权限Auth,在Ubuntu终端下输入:
- lingaohe@lingaohe-laptop:~$ curl -d "accountType=HOSTED_OR_GOOGLE&Email=android.c2dm.demo@gmail.com&Passwd=androidc2dmdemo&service=ac2dm&source=bupt-c2dmdemo-1.0" https://www.google.com/accounts/ClientLogin
这个表示以POST的方式向https://www.google.com/accounts/ClientLogin发送数据,其中把Email和Passwd换成你本身在C2DM网页上注册的邮箱号和密码。
若是你的邮箱已在C2DM网页上注册,而且密码没有错误的话就会返回须要的Auth内容:
- SID=DQAAAKYAAADcTtHbBBNcZJEOfkfVRycD_ZOIidwsQ3UwIY7cSrYWaY6uhlfo0l9gRPB-mQxP4K2T5tWiG--vWVmSTeq5p8SPwgnsYvfzj7bkNiPPIy4xRimVVfBmAHnZgLohw7gHMKi5DS6kK-Ut5tNzdTkI0I2tUDF0ryQ7MnPpI6Sj-gUCyBXmvKatHHDnNTTV78XdGIx7FYej1DyqGsPsYo3bCstHgltjv3cd2Hs7D4yrpUWHZw
- LSID=DQAAAKgAAABCpaoUE4XvxM24Cofntw1IUGx5fKxX-m7aqTL0zhunP0OjzJ2sn9ywmPa1BMZ2cF2IchuxHFLVzaSQfydAmiHZJGXLgaUorpIN6yz1e0VFWKmS6j4wGjZOos3QoJ9rkha0jKbOiHfBesADjxk-qjJ24TJ0RL-xkZHQyzS69YlA1KyzqIKjAMCzgqaDfCwhqxylJzizJksO2h8xpAFXZ38d_grm8XYZtzejiCiAMAR65A
- Auth=DQAAAKoAAACRF4pgYULnXULoWgbwfdqmMiRhfZYa1l-LW_rwGD7cofov4L4c2bVrtCOXbEbkju_hhqdAonpMkrb5icptt28fU8c-s-u1y2MXNYDxPIdQzfA2t6oI3NTmyj35MpsR1NKL4TN7ZVEn6z9NueuiKAqLHukZYh1YMGkGC8M6rVvA7AWPW36064XCQED7KLVNp_pGT00lrni7UdZKZWEy0FT-EVR-OxDyHWw6C-5Kmfkisw
返回的内容包括SID,LSID和Auth三个部分,其中Auth是咱们须要的内容。
有了Auth和registration_id值后,咱们就能够继续用curl命令模拟咱们本身服务器的功能向C2DM发送要推送的数据:
- lingaohe@lingaohe-laptop:~$ curl -H "Authorization:GoogleLogin auth=DQAAAKoAAACRF4pgYULnXULoWgbwfdqmMiRhfZYa1l-LW_rwGD7cofov4L4c2bVrtCOXbEbkju_hhqdAonpMkrb5icptt28fU8c-s-u1y2MXNYDxPIdQzfA2t6oI3NTmyj35MpsR1NKL4TN7ZVEn6z9NueuiKAqLHukZYh1YMGkGC8M6rVvA7AWPW36064XCQED7KLVNp_pGT00lrni7UdZKZWEy0FT-EVR-OxDyHWw6C-5Kmfkisw" -d "registration_id=APA91bGUBoSvt3G5Ny9t0IGLmIKAKYX6G6VHwSQHh3tP2fqcaQ0N4GPdKh5B3RDUHFCFF06YwT8ifOP_cOy5BAWyCLHL8d8NpuIW9AqXt9h2JSBVF2MitZA&collapse_key=1&data.msg=ichliebejiajia" https://android.apis.google.com/c2dm/send
其中发送的数据部分为data.msg=ichliebejiajia,表示发送的数据内容为ichliebejiajia,键值为msg,键值得和Android终端上的程序统一好,以便终端上能够获取。若是发送成功,会返回一个id值,好比:
- id=0:1308623423080544%6c5c15c200000031
- lingaohe@lingaohe-laptop:~$
这时咱们的服务器就已经把数据发送给C2DM服务器了,Android设备上一会就能接收到C2DM服务器Push的数据。
在咱们的例子中咱们能够看到DDMS中打印出的消息:
图7 获取到的Push数据
同时Android模拟器的状态栏上会有对应的通知显示:
图8 Android模拟器接收到的Push数据
这样咱们就快速实现了下Android的C2DM框架的Push功能。进一步的具体解释说明及服务器端的代码处理咱们之后再学习。
文章对应的完整代码例子下载地址:
http://download.csdn.net/source/3425855