Android C2DM学习 - 云端推送
一、基礎知識
當我們開發(fā)需要和服務器交互的應用程序時,基本上都需要獲取服務器端的數(shù)據(jù),比如《地震及時通》就需要及時獲取服務器上最新的地震信息。要獲取服務器上不定時更新的信息一般來說有兩種方法,第一種是客戶端使用Pull(拉)的方式,隔一段時間就去服務器上獲取信息,看是否有更新的信息出現(xiàn)。第二種就是服務器使用Push(云端推送)的方式,當服務器端有新信息了,則把最新的信息Push到客戶端上。
雖然Pull和Push兩種方式都能實現(xiàn)獲取服務器端更新信息的功能,但是明顯來說Push is better than pull。因為Pull方式不僅浪費客戶端的流量,而且更浪費電量。
Android從2.2版本開始增加了Cloud to Device Messaging(C2DM)框架,在系統(tǒng)中支持了Push功能,基于Android平臺使用Push功能更加簡單了。雖然C2dm目前還處在實驗室階段,不過小規(guī)模的使用是沒有問題的。
下面我們就來感受一下Android的C2dm功能。
二、C2DM框架
使用Android的C2DM功能有幾個要求:
1. 需要Android2.2及以上的系統(tǒng)版本。
2. 使用C2DM功能的Android設備上需要設置好Google的賬戶。
3. 需要在這里注冊使用C2DM功能的用戶郵箱賬號(最好為C2DM單獨注冊一個Gmail郵箱賬號)。
接下來我們來看下C2dm的完整過程,這里借用一下Google官方推出的Chrome To Phone過程圖來說明下。
圖1 C2DM操作過程圖
要使用C2DM來進行Push操作,基本上要使用以下6個步驟:
1、注冊:Android設備把使用C2DM功能的用戶賬戶(比如android.c2dm.demo@gmail.com)和App名稱發(fā)送給C2DM服務器。
2、C2dm服務器會返回一個registration_id值給Android設備,設備需要保存這個registration_id值。
3、Android設備把獲得的registration_id和C2DM功能的用戶賬戶(android.c2dm.demo@gmail.com)發(fā)送給自己的服務器,不過一般用戶賬戶信息因為和服務器確定好的,所以不必發(fā)送。
這樣Android設備就完成了C2DM功能的注冊過程,接下來就可以接收C2DM服務器Push過來的消息了。
4、服務器獲得數(shù)據(jù)。這里圖中的例子Chrome To Phone,服務器接收到Chrome瀏覽器發(fā)送的數(shù)據(jù)。數(shù)據(jù)也可以是服務器本地產(chǎn)生的。這里的服務器是Google AppEngine(很好的一項服務,可惜在國內被屏了),要換成自己的服務器。服務器還要獲取注冊使用C2DM功能的用戶賬戶(android.c2dm.demo@gmail.com)的ClientLogin權限Auth。
5、服務器把要發(fā)送的數(shù)據(jù)和registration_id一起,并且頭部帶上獲取的Auth,使用POST的方式發(fā)送給C2dm服務器。
6、C2DM服務器會以Push的方式把數(shù)據(jù)發(fā)送給對應的Android設備,Android設備只要在程序中按之前和服務器商量好的格式從對應的key中獲取數(shù)據(jù)即可。
這樣我們就大概明白了C2dm的工作流程,下面我們就結合一個實例來具體的說明以上6個步驟。
三.實例開發(fā)
我們要創(chuàng)建的程序名稱為AndroidC2DMDemo,包名為com.ichliebephone.c2dm。
開始之前我們先去C2DM網(wǎng)頁上注冊一下使用C2DM功能的用戶賬戶。
圖2 應用程序名
其中應用程序名要填寫帶包名的完整名稱,比如這里為om.ichliebephone.c2dm. AndroidC2DMDemo。
圖3 C2DM用戶賬戶注冊
這里的contact郵箱使用一個你能接收到郵件的郵箱即可,下面的Role(sender)account郵箱最好單獨注冊一個Gmail郵箱來使用C2DM服務。我們這里使用的是專門注冊的android.c2dm.deno@gmail.com郵箱。
提交后,過一段時間就會收到Google發(fā)送過來的確認郵件,然后你就可以使用C2DM的Push服務了。
介紹了這么多,我們先來快速完成一個實例,只完成Android設備端的注冊部分,不包含向服務器發(fā)送registration_id和服務器向C2DM服務器發(fā)送數(shù)據(jù)的具體代碼,這部分只是用Ubuntu下的curl命令來模擬,主要是快速親自體驗一下Push的結果。
創(chuàng)建一個Android工程AndroidC2DMDemo,并且包含進Google的開源例子Chrome To Phone中的c2dm包com.google.android.c2dm,包中包含三個Java類,分別為:
第一個類為C2DMBaseReceiver:
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過來的信息后的回調函數(shù),都可以在繼承的子類中處理 /** * Called when a cloud message has been received. */ /** * 接收到C2DM服務器Push的消息后的回調函數(shù),需要在繼承的子類中處理 * */ 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. */ /** * 出錯的回調函數(shù) * */ public abstract void onError(Context context, String errorId); /** * Called when a registration token has been received. */ /** * 注冊后的回調函數(shù) * */ public void onRegistered(Context context, String registrationId) throws IOException { // registrationId will also be saved } /** * Called when the device has been unregistered. */ /** * 取消注冊的回調函數(shù) * */ 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:
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. */ /** * 和注冊相關的一些實用函數(shù) * */ 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(); } }代碼中已添加了部分中文注釋,可以先大概了解下,等整個工程建立完了在一起解釋。
然后創(chuàng)建我們自己的包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消息,推送的數(shù)據(jù)消息等 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消息的回調函數(shù) @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的回調函數(shù)onMessage中對消息進行了接收,并且使用Notification的方式顯示在狀態(tài)欄上。
我們完整的工程目錄是這樣的:
圖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 --> <!-- 設置聯(lián)網(wǎng)權限,在把registration_id發(fā)送給服務器的時候要用 --> <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服務只為這個程序發(fā)送數(shù)據(jù),聲明對應的權限 --> <receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND"> <!-- Receive the actual message --> <!-- 可以接收實際的Push數(shù)據(jù) --> <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系統(tǒng)才支持,因此創(chuàng)建一個2.2及以上的AVD,然后在”設置->賬戶與同步”里還要設置好Google Account,如下圖所示:
圖5 設置Android設備中的Google賬戶
然后就可以運行程序了,我們會在DDMS輸出中看到獲得的registration_id:
圖6 獲得的registration_id
如果第一次運行沒有出現(xiàn),試著再運行一次。
有了registration_id,我們的服務器端就可以向C2DM端發(fā)送需要Push的數(shù)據(jù)了,這里進行簡單化處理下,在Ubuntu下直接使用curl命令來模擬服務器功能向C2DM發(fā)送數(shù)據(jù)。
我們先來獲取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發(fā)送數(shù)據(jù),其中把Email和Passwd換成你自己在C2DM網(wǎng)頁上注冊的郵箱號和密碼。
如果你的郵箱已在C2DM網(wǎng)頁上注冊,并且密碼沒有錯誤的話就會返回需要的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值后,我們就可以繼續(xù)用curl命令模擬我們自己服務器的功能向C2DM發(fā)送要推送的數(shù)據(jù):
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其中發(fā)送的數(shù)據(jù)部分為data.msg=ichliebejiajia,表示發(fā)送的數(shù)據(jù)內容為ichliebejiajia,鍵值為msg,鍵值得和Android終端上的程序統(tǒng)一好,以便終端上可以獲取。如果發(fā)送成功,會返回一個id值,比如:
id=0:1308623423080544%6c5c15c200000031 lingaohe@lingaohe-laptop:~$這時我們的服務器就已經(jīng)把數(shù)據(jù)發(fā)送給C2DM服務器了,Android設備上一會就能接收到C2DM服務器Push的數(shù)據(jù)。
在我們的例子中我們可以看到DDMS中打印出的消息:
圖7 獲取到的Push數(shù)據(jù)
同時Android模擬器的狀態(tài)欄上會有對應的通知顯示:
圖8 Android模擬器接收到的Push數(shù)據(jù)
這樣我們就快速實現(xiàn)了下Android的C2DM框架的Push功能。進一步的具體解釋說明及服務器端的代碼處理我們以后再學習。
總結
以上是生活随笔為你收集整理的Android C2DM学习 - 云端推送的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux网络服务之DNS(1)
- 下一篇: oracle mysql sql s