




已阅读5页,还剩14页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android C2DM云端推送一基础知识当我们开发需要和服务器交互的应用程序时,基本上都需要获取服务器端的数据,比如地震及时通就需要及时获取服务器上最新的地震信息。要获取服务器上不定时更新的信息一般来说有两种方法,第一种是客户端使用Pull(拉)的方式,隔一段时间就去服务器上获取信息,看是否有更新的信息出现。第二种就是服务器使用Push(推送)的方式,当服务器端有新信息了,则把最新的信息Push到客户端上。虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能,但是明显来说Push is better than pull。因为Pull方式更费客户端的网络流量,更主要的是费电量。Android从2.2版本开始增加了Cloud to Device Messaging(C2DM)框架,在系统中支持了Push功能,基于Android平台使用Push功能更加简单了。虽然C2DM目前还处在实验室阶段,不过小规模的使用应该没问题下面我们就来体验一下Android的C2DM功能。二C2DM框架使用Android的C2DM功能有几个要求:1. 需要Android2.2及以上的系统版本。2. 使用C2DM功能的Android设备上需要设置好Google的账户。3. 需要在这里注册使用C2DM功能的用户邮箱账号(最好为C2DM单独注册一个Gmail邮箱账号)。我们接下来C2DM的一个完整过程,这里借用一下Google官方推出的Chrome To Phone过程图来说明下。 图1 C2DM操作过程图要使用C2DM来进行Push操作,基本上要使用以下6个步骤: (1)注册:Android设备把使用C2DM功能的用户账户(比如)和App名称发送给C2DM服务器。 (2)C2DM服务器会返回一个registration_id值给Android设备,设备需要保存这个registration_id值。 (3)Android设备把获得的registration_id和C2DM功能的用户账户()发送给自己的服务器,不过一般用户账户信息因为和服务器确定好的,所以不必发送。这样Android设备就完成了C2DM功能的注册过程,接下来就可以接收C2DM服务器Push过来的消息了。 (4)服务器获得数据。这里图中的例子Chrome To Phone,服务器接收到Chrome浏览器发送的数据。数据也可以是服务器本地产生的。这里的服务器是Google AppEngine(很好的一项服务,可惜在国内被屏了),要换成自己的服务器。服务器还要获取注册使用C2DM功能的用户账户()的ClientLogin权限Auth。 (5)服务器把要发送的数据和registration_id一起,并且头部带上获取的Auth,使用POST的方式发送给C2DM服务器。 (6)C2DM服务器会以Push的方式把数据发送给对应的Android设备,Android设备只要在程序中按之前和服务器商量好的格式从对应的key中获取数据即可。 这样我们就大概明白了C2DM的工作流程,下面我们就结合一个实例来具体的说明以上6个步骤。三实例开发我们要创建的程序名称为AndroidC2DMDemo,包名为com.ichliebephone.c2dm。开始之前我们先去C2DM网页上注册一下使用C2DM功能的用户账户。 其中应用程序名要填写带包名的完整名称,比如这里为om.ichliebephone.c2dm. AndroidC2DMDemo。 这里的contact邮箱使用一个你能接收到邮件的邮箱即可,下面的Role(sender)account邮箱最好单独注册一个Gmail邮箱来使用C2DM服务。我们这里使用的是专门注册的邮箱。 提交后,过一段时间就会收到Google发送过来的确认邮件,然后你就可以使用C2DM的Push服务了。 介绍了这么多,我们先来快速完成一个实例,只完成Android设备端的注册部分,不包含向服务器发送registration_id和服务器向C2DM服务器发送数据的具体代码,这部分只是用Ubuntu下的curl命令来模拟,主要是快速亲自体验一下Push的结果。创建一个Android工程AndroidC2DMDemo,并且包含进Google的开源例子Chrome To Phone中的c2dm包com.google.android.c2dm,包中包含三个Java类,分别为:第一个类为C2DMBaseReceiver:java view plaincopy1 /* 2 * Copyright 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the License); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * /licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an AS IS BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.android.c2dm; 18 19 import java.io.IOException; 20 21 import android.app.AlarmManager; 22 import android.app.IntentService; 23 import android.app.PendingIntent; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.os.PowerManager; 27 import android.util.Log; 28 29 /* 30 * Base class for C2D message receiver. Includes constants for the 31 * strings used in the protocol. 32 */ 33 /* 34 * 接收和处理C2DM消息的基类 35 * */ 36 public abstract class C2DMBaseReceiver extends IntentService 37 /和C2DM Push的Intent内容相关 38 /重新向C2DM服务器注册 39 private static final String C2DM_RETRY = ent.RETRY; 40 /向C2DM服务器注册后的回调处理 41 public static final String REGISTRATION_CALLBACK_INTENT = ent.REGISTRATION; 42 /接收到C2DM服务器的推送消息 43 private static final String C2DM_INTENT = ent.RECEIVE; 44 45 / Logging tag 46 private static final String TAG = C2DM; 47 48 / Extras in the registration callback intents. 49 /向C2DM注册返回的intent中包含的key 50 public static final String EXTRA_UNREGISTERED = unregistered; 51 public static final String EXTRA_ERROR = error; 52 public static final String EXTRA_REGISTRATION_ID = registration_id; 53 /向C2DM注册出错的原因 54 public static final String ERR_SERVICE_NOT_AVAILABLE = SERVICE_NOT_AVAILABLE; 55 public static final String ERR_ACCOUNT_MISSING = ACCOUNT_MISSING; 56 public static final String ERR_AUTHENTICATION_FAILED = AUTHENTICATION_FAILED; 57 public static final String ERR_TOO_MANY_REGISTRATIONS = TOO_MANY_REGISTRATIONS; 58 public static final String ERR_INVALID_PARAMETERS = INVALID_PARAMETERS; 59 public static final String ERR_INVALID_SENDER = INVALID_SENDER; 60 public static final String ERR_PHONE_REGISTRATION_ERROR = PHONE_REGISTRATION_ERROR; 61 62 / wakelock 63 private static final String WAKELOCK_KEY = C2DM_LIB; 64 65 private static PowerManager.WakeLock mWakeLock; 66 private final String senderId; 67 68 /* 69 * The C2DMReceiver class must create a no-arg constructor and pass the 70 * sender id to be used for registration. 71 */ 72 public C2DMBaseReceiver(String senderId) 73 / senderId is used as base name for threads, etc. 74 super(senderId); 75 this.senderId = senderId; 76 77 /下面几个是接收到C2DM Push过来的信息后的回调函数,都可以在继承的子类中处理 78 /* 79 * Called when a cloud message has been received. 80 */ 81 /* 82 * 接收到C2DM服务器Push的消息后的回调函数,需要在继承的子类中处理 83 * */ 84 protected abstract void onMessage(Context context, Intent intent); 85 86 /* 87 * Called on registration error. Override to provide better 88 * error messages. 89 * 90 * This is called in the context of a Service - no dialog or UI. 91 */ 92 /* 93 * 出错的回调函数 94 * */ 95 public abstract void onError(Context context, String errorId); 96 97 /* 98 * Called when a registration token has been received. 99 */ 100 /* 101 * 注册后的回调函数 102 * */ 103 public void onRegistered(Context context, String registrationId) throws IOException 104 / registrationId will also be saved 105 106 107 /* 108 * Called when the device has been unregistered. 109 */ 110 /* 111 * 取消注册的回调函数 112 * */ 113 public void onUnregistered(Context context) 114 115 116 /IntentService的方法 117 Override 118 public final void onHandleIntent(Intent intent) 119 try 120 Context context = getApplicationContext(); 121 if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT) 122 handleRegistration(context, intent);/处理注册后的回调 123 else if (intent.getAction().equals(C2DM_INTENT) 124 onMessage(context, intent);/处理C2DM Push消息的回调 125 else if (intent.getAction().equals(C2DM_RETRY) 126 C2DMessaging.register(context, senderId); /重新注册 127 128 finally 129 / Release the power lock, so phone can get back to sleep. 130 / The lock is reference counted by default, so multiple 131 / messages are ok. 132 133 / If the onMessage() needs to spawn a thread or do something else, 134 / it should use its own lock. 135 mWakeLock.release(); 136 137 138 139 140 /* 141 * Called from the broadcast receiver. 142 * Will process the received intent, call handleMessage(), registered(), etc. 143 * in background threads, with a wake lock, while keeping the service 144 * alive. 145 */ 146 static void runIntentInService(Context context, Intent intent) 147 if (mWakeLock = null) 148 / This is called from BroadcastReceiver, there is no init. 149 PowerManager pm = 150 (PowerManager) context.getSystemService(Context.POWER_SERVICE); 151 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 152 WAKELOCK_KEY); 153 154 mWakeLock.acquire(); 155 156 / Use a naming convention, similar with how permissions and intents are 157 / used. Alternatives are introspection or an ugly use of statics. 158 String receiver = context.getPackageName() + .C2DMReceiver; 159 intent.setClassName(context, receiver); 160 161 context.startService(intent); 162 163 164 165 /处理注册后的回调 166 private void handleRegistration(final Context context, Intent intent) 167 final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID); 168 String error = intent.getStringExtra(EXTRA_ERROR); 169 String removed = intent.getStringExtra(EXTRA_UNREGISTERED); 170 Log.v(TAG, handleRegistration); 171 /打印出接收到的registraton_id 172 Log.v(TAG, dmControl: registrationId = + registrationId + 173 , error = + error + , removed = + removed); 174 if (Log.isLoggable(TAG, Log.DEBUG) 175 Log.d(TAG, dmControl: registrationId = + registrationId + 176 , error = + error + , removed = + removed); 177 178 if (removed != null) 179 / Remember we are unregistered 180 C2DMessaging.clearRegistrationId(context); 181 onUnregistered(context); 182 return; 183 else if (error != null) 184 / we are not registered, can try again 185 C2DMessaging.clearRegistrationId(context); 186 / Registration failed 187 Log.e(TAG, Registration error + error); 188 onError(context, error); 189 if (SERVICE_NOT_AVAILABLE.equals(error) 190 long backoffTimeMs = C2DMessaging.getBackoff(context); 191 192 Log.d(TAG, Scheduling registration retry, backoff = + backoffTimeMs); 193 Intent retryIntent = new Intent(C2DM_RETRY); 194 PendingIntent retryPIntent = PendingIntent.getBroadcast(context, 195 0 /*requestCode*/, retryIntent, 0 /*flags*/); 196 197 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 198 am.set(AlarmManager.ELAPSED_REALTIME, 199 backoffTimeMs, retryPIntent); 200 201 / Next retry should wait longer. 202 backoffTimeMs *= 2; 203 C2DMessaging.setBackoff(context, backoffTimeMs); 204 205 else 206 try 207 onRegistered(context, registrationId); 208 C2DMessaging.setRegistrationId(context, registrationId); 209 catch (IOException ex) 210 Log.e(TAG, Registration error + ex.getMessage(); 211 212 213 214 第二个类为C2DMBroadcastReceiver:java view plaincopy215 /* 216 */ 217 package com.google.android.c2dm; 218 219 import android.app.Activity; 220 import android.content.BroadcastReceiver; 221 import android.content.Context; 222 import android.content.Intent; 223 224 /* 225 * Helper class to handle BroadcastReciver behavior. 226 * - can only run for a limited amount of time - it must start a real service 227 * for longer activity 228 * - must get the power lock, must make sure its released when all done. 229 * 230 */ 231 /* 232 * 帮助类,帮忙处理BroadcastReciver过程 233 * */ 234 public class C2DMBroadcastReceiver extends BroadcastReceiver 235 236 Override 237 public final void onReceive(Context context, Intent intent) 238 / To keep things in one place. 239 C2DMBaseReceiver.runIntentInService(context, intent); 240 setResult(Activity.RESULT_OK, null /* data */, null /* extra */); 241 242 第三个类为C2DMessaging:java view plaincopy243 /* 244 * Copyright 2010 Google Inc. 245 * 246 * Licensed under the Apache License, Version 2.0 (the License); 247 * you may not use this file except in compliance with the License. 248 * You may obtain a copy of the License at 249 * 250 * /licenses/LICENSE-2.0 251 * 252 * Unless required by applicable law or agreed to in writing, software 253 * distributed under the License is distributed on an AS IS BASIS, 254 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 255 * See the License for the specific language governing permissions and 256 * limitations under the License. 257 */ 258 259 package com.google.android.c2dm; 260 261 import android.app.PendingIntent; 262 import android.content.Context; 263 import android.content.Intent; 264 import android.content.SharedPreferences; 265 import android.content.SharedPreferences.Editor; 266 267 /* 268 * Utilities for device registration. 269 * 270 * Will keep track of the registration token in a private preference. 271 */ 272 /* 273 * 和注册相关的一些实用函数 274 * */ 275 public class C2DMessaging 276 public static final String EXTRA_SENDER = sender; 277 public static final String EXTRA_APPLICATION_PENDING_INTENT = app; 278 public static final String REQUEST_UNREGISTRATION_INTENT = ent.UNREGISTER; 279 public static final String REQUEST_REGISTRATION_INTENT = ent.REGISTER; 280 public static final String LAST_REGISTRATION_CHANGE = last_registration_change; 281 public static final String BACKOFF = backoff; 282 public static final String GSF_PACKAGE = com.google.android.gsf; /GSF为GoogleServicesFramework.apk的缩写 283 284 285 / package 286 static final String PREFERENCE = com.google.android.c2dm; 287 288 private static final long DEFAULT_BACKOFF = 30000; 289 290 /* 291 * Initiate c2d messaging registration for the current application 292 */ 293 public static void register(Context context, 294 String senderId) 295 Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT); 296 registrationIntent.setPackage(GSF_PACKAGE); 297 registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, 298 PendingIntent.getBroadcast(context, 0, new Intent(), 0); 299 registrationIntent.putExtra(EXTRA_SENDER, senderId); 300 context.startService(registrationIntent); 301 / TODO: if intent not found, notification on need to have GSF 302 303 304 /* 305 * Unregister the application. New messages will be blocked by server. 306 */ 307 public static void unregister(Context context) 308 Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT); 309 regIntent.setPackage(GSF_PACKAGE); 310 regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context, 311 0, new Intent(), 0); 312 context.startService(regIntent); 313 314 315 /* 316 * Return the current registration id. 317 * 318 * If result is empty, the registration has failed. 319 * 320 * return registration id, or empty string if the registration is not complete. 321 */ 322 public static String getRegistrationId(Context context) 323 final SharedPreferences prefs = context.getSharedPreferences( 324 PREFERENCE, 325 Context.MODE_PRIVATE); 326 String registrationId = prefs.getString(dm_registration, ); 327 return registrationId; 328 329 330 public static long getLastRegistrationChange(Context context) 331 final SharedPreferences prefs = context.getSharedPreferences( 332 PREFERENCE, 333 Context.MODE_PRIVATE); 334 return prefs.getLong(LAST_REGISTRATION_CHANGE, 0); 335 336 337 static long getBackoff(Context context) 338 final SharedPreferences prefs = context.getSharedPreferences( 339 PREFERENCE, 340 Context.MODE_PRIVATE); 341 return prefs.getLong(BACKOFF, DEFAULT_BACKOFF); 342 343 344 static void setBackoff(Context context, long backoff) 345 final SharedPreferences prefs = context.getSharedPreferences( 346 PREFERENCE, 347 Context.MODE_PRIVATE); 348 Editor editor = prefs.edit(); 349 editor.putLong(BACKOFF, backoff); 350 mit(); 351 352 353 354 / package 355 static void clearRegistrationId(Context context) 356 final SharedPreferences prefs = context.getSharedPreferences( 357 PREFERENCE, 358 Context.MODE_PRIVATE); 359 Editor editor = prefs.edit(); 360 editor.putString(dm_registration, ); 361 editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMil
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年计算机科学试题及答案解析
- 2025年护理学专业资格考试试题及答案解析
- 2025年汉语教师职业技能考试试题及答案解析
- 2025年国际贸易法务专家资格考试试题及答案解析
- 2025年导盲犬训练师面试高频题
- 课件中任务卡模板制作步骤
- 课件中video的缩写形式
- 2025年小美容院美容安全考核题及答案
- 三礼教学课件
- 2025年地震避险知识题库含全解
- 口服CCB类药品临床综合评价指标体系专家咨询调查表
- 第四节道亨slw2d架空送电线路评断面处理及定位设计系统部分操作说明
- 测振仪使用方法
- 2023-2024学年湖南省耒阳市小学语文六年级下册期末自测测试题
- 表- 邻二氯苯的理化性质和危险特性表
- 工程项目全过程造价管理课件PPT超详细
- 成人手术后疼痛处理专家共识
- 读书分享-《教育的情调》
- 《材料力学》说课-课件
- 物资采购付款报销单
- 政务云收费标准 云托管收费标准
评论
0/150
提交评论