`

Android C2DM学习——客户端代码开发

 
阅读更多

一.基础知识

    在前一部分中,我们从整体上快速介绍并实现了下Android C2DM的Push功能,在接下来的部分里,我们先来回顾一下C2DM相关的整体上的知识,然后具体介绍说明实现的过程。

    在前面的C2DM框架说明中,我们已经知道,要实现Android的C2DM推送功能,需要涉及到三个功能实体:

    1. Android设备:推送消息的接收端,在上面会运行我们的客户端程序

    2. 第三方服务器:这是我们自己控制的服务器,推送消息的发送端,利用C2DM服务器发送我们要推送的消息

    3. C2DM服务器:这是Google已经实现好的服务器,接收我们服务器的数据并把他们发送给对应的Android设备

    这三个功能实体部分,其中C2DM服务器是谷歌开发并且已经实现好的,我们只需按其要求的格式与其进行交互即可。我们自己要开发的为另两个实体部分:Android设备上运行的客户端程序的开发和实现第三方服务器上的功能。

    并且在整个完整的C2DM推送过程中,要涉及到一些验证用的信息:

    1. Sender ID:这是我们前面说过的在这里注册的账号,这个Sender ID主要用来当Android设备上的客户端程序向C2DM服务器注册的时候验证其有使用C2DM服务的权限。

    2. Application ID:使用C2DM功能的完整应用程序名,主要用来确保接收到的Push信息绑定到正确的应用程序。

    3. Registration ID:这是Android设备上的客户端程序向C2DM服务器注册成功后返回的ID,然后客户端程序需要把这个ID发送给第三方服务器,然后第三方服务器使用这个ID值来向这个设备推送信息。

    4. Google User Account:需要在Android设备上登录的谷歌账户,因为C2DM服务是通过已经建立连接的谷歌后台服务来找到对应消息要推送的设备。这个账户验证信息只要在设备上登陆即可,不需要在客户端程序中出现。

    5. Sender Auth Token:这是第一个Sender ID对应的使用C2DM服务的权限,在第三方服务器的程序中向Google申请,并且向C2DM服务器发送要推送的消息时要附带这个信息。

    这5个和验证相关的信息中,前4个在Android设备上的客户端程序中都有相关,第三方服务器上的程序要使用第3个和第5个验证信息。

    最后我们再从整体上来看下Cloud-To-Device Message的主要处理过程,更概括的话可以分为三个步骤:

    1. 使能C2DM功能:第一步为Android设备上的客户端程序向C2DM服务器注册,允许接收C2DM的推送消息。

    2. 发送推送消息:第二步为第三方服务器通过C2DM服务器向Android设备发送推送信息。

    3.  接收推送信息:第三步为Android设备上的客户端程序接收来自C2DM服务器的推送消息。

    其中第一步和第三步是在Android设备上的客户端程序中实现,第二步是在第三方服务器上实现。

     我们知道完整的C2DM推送功能要涉及Android设备客户端和第三方服务器两方面程序的开发,下面我们首先来具体学习客户端部分的代码开发。

二.客户端开发说明

    客户端要实现两个步骤,使能C2DM功能和接收推送消息。

    使能C2DM功能,即客户端程序向Google的C2DM服务器注册C2DM服务,使程序允许接收推送消息,过程包含以下三个步骤:

    1. 首先客户端程序需要向C2DM服务器启动注册需要的registration Intent。

    这个registration Intent(com.google.android.c2dm.intent.REGISTER)需要包含两个内容信息:一个是Sender ID;另一个是Application ID;即我们上面说到的验证信息的前两个。

    2. 如果注册成功,C2DM服务器会广播一个com.google.android.c2dm.intent. REGISTRATION Intent,我们的客户端程序需要响应并接收这个Intent,并且从其中获取注册成功返回的Registration ID。

    为了后面的使用,客户端程序需要保存这个Registration ID。因为Google可能不定时更新Registration ID值,并通过REGISTRATION Intent进行告知,因此我们的程序需要能进行对应的响应,获取新的Registration ID值并更新保存。

    3. 为了完成注册过程,最后一步是我们的客户端程序需要把获得的Registration ID值发送给我们的第三方服务器,并且一般来说第三方服务器要把Registration ID值保存在数据库中。

    客户端程序也可以发送com.google.android.c2dm.intent.UNREGISTER Intent取消注册,从而不再接收C2DM服务器发送的推送信息。

    Android设备接收推送信息的过程包含以下三个步骤:

    1. Android系统获取C2DM服务器推送过来的信息,并且从信息内容中提取键值对数据。

    2. Android系统向对应的客户端程序发送com.google.android.c2dm.intent.RECEIVE Intent并在其中包含键值对数据。

    3. 客户端程序响应RECEIVE Intent并从中提取出键值对数据,最后根据之前就和发送数据的第三方服务器端商量好的键值,提取对应的数据。

    前面介绍了很多相关知识,接下来我们重新实现一下客户端的代码。

三.实例开发

    为了能继续使用之前的Sender ID邮箱及已经注册好的应用程序名等信息,我们还是创建一样名为AndroidC2DMDemo的工程。先删除原来的工程或者把Eclipse切换到另一个Workspace下。

    创建AndroidC2DMDemo工程,并且包名为com.ichliebephone.c2dm,Min SDK Version选择8。

    为了使用C2DM服务,客户端程序要进行两部分处理,

    1. 在Manifest.xml文件中声明和C2DM相关的权限。

    2. 在Java代码中实现C2DM相关的功能,如前面说的:

        a)和C2DM注册相关的代码

        b)接收C2DM服务器推送信息相关的代码

    下面我们先来实现Java代码部分。

    新建一个类C2DMRegistration,用来实现C2DM注册相关功能。

  1. public class C2DMRegistration {  
  2.   
  3.     //注册C2DM服务  
  4.     public static void register(Context context, String senderID){  
  5.         Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");  
  6.         registrationIntent.putExtra("app", PendingIntent.getBroadcast(context, 0new Intent(), 0)); // boilerplate  
  7.         registrationIntent.putExtra("sender", senderID);  
  8.         context.startService(registrationIntent);  
  9.     }  
  10.     //取消C2DM服务  
  11.     public static void unregister(Context context){  
  12.         Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");  
  13.         unregIntent.putExtra("app", PendingIntent.getBroadcast(context, 0new Intent(), 0));  
  14.         context.startService(unregIntent);  
  15.     }  
  16.     //保存注册成功获得的registration_id值  
  17.     static void setRegistraionID(Context context, String registrationId){  
  18.         final SharedPreferences prefs = context.getSharedPreferences(  
  19.                 "c2dm_preference",  
  20.                 Context.MODE_PRIVATE);  
  21.         Editor editor = prefs.edit();  
  22.         editor.putString("dm_registration", registrationId);  
  23.         editor.commit();  
  24.     }  
  25.     //获取保存的registration_id值  
  26.     public static String getRegistrationID(Context context){  
  27.         final SharedPreferences prefs = context.getSharedPreferences(  
  28.                 "c2dm_preference",  
  29.                 Context.MODE_PRIVATE);  
  30.         String registrationId = prefs.getString("dm_registration""");  
  31.         return registrationId;  
  32.     }  
  33.     //当取消C2DM服务时,清空之前保存着的registration_id值  
  34.     static void clearRegistrationId(Context context) {  
  35.         final SharedPreferences prefs = context.getSharedPreferences(  
  36.                 "c2dm_preference",  
  37.                 Context.MODE_PRIVATE);  
  38.         Editor editor = prefs.edit();  
  39.         editor.putString("dm_registration""");  
  40.         editor.commit();  
  41. }  
  42.     //当SERVICE_NOT_AVAILABLE时,需要回退一定时间后重新启动注册  
  43.     //获取当前的回退等待时间  
  44.     static long getBackoff(Context context) {  
  45.         final SharedPreferences prefs = context.getSharedPreferences(  
  46.                 "c2dm_preference",  
  47.                 Context.MODE_PRIVATE);  
  48.         //默认回退等待时间为30000微秒  
  49.         return prefs.getLong("back_off"30000);  
  50.     }  
  51.     //设置回退等待时间  
  52.     static void setBackoff(Context context, long backoff) {  
  53.         final SharedPreferences prefs = context.getSharedPreferences(  
  54.                 "c2dm_preference",  
  55.                 Context.MODE_PRIVATE);  
  56.         Editor editor = prefs.edit();  
  57.         editor.putLong("back_off", backoff);  
  58.         editor.commit();  
  59.     }  
  60. }  

    这个类主要实现了下向C2DM服务器发起和取消注册,并且本地保存、清除和获取注册成功获得的registration_id值,同时还有一个和重新启动注册相关的回退时间值的设置与获取。

    其中注册方法很简单,就是发送一个com.google.android.c2dm.intent.REGISTER的Intent,其中包含两个参数,一个是在C2DM网页上注册的Sender ID邮箱,另一个是程序的ID值。

    取消注册的方法就是发送一个带有程序ID值的com.google.android.c2dm.intent.UNREGISTER这样的Intent。

    并且使用Perference键值对的方式保存获取的registration_id值。

    接着再新建一个类C2DMReceiver,用来处理接收到的C2DM服务器的数据。

    客户端程序会接收到C2DM服务器的两种类型数据,并且这两种类型的数据都是通过Intent的方式来处理的。一种类型是向C2DM服务器注册后的回调数据,这时Intent对应的Action为com.google.android.c2dm.intent.REGISTRATION;另一种类型是C2DM正式的推送数据,此时Intent对应的Action为com.google.android.c2dm.intent.RECEIVE。

    因为C2DMReceiver主要是用来接收Intent,因此需要扩展自BroadcastReceiver。对应的onReceive方法主要就是判断接收C2DM的两种类型数据:

  1. @Override  
  2.     public void onReceive(Context context, Intent intent) {  
  3.         // TODO Auto-generated method stub  
  4.         if(intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")){  
  5.             //如果是注册返回的Intent  
  6.             handleRegistration(context, intent);  
  7.         }else if(intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")){  
  8.             //如果是接收到C2DM推送消息的Intent  
  9.             handleMessage(context, intent);  
  10.         }  
  11.     }  

 

     当是接收到注册返回的Intent时,就调用handleRegistration方法:

 

  1. //注册后的回调处理  
  2. private void handleRegistration(final Context context, Intent intent){  
  3.     //如果是注册成功,则Intent中包含"registration_id"键对应的值  
  4.        final String registrationId = intent.getStringExtra("registration_id");  
  5.        //如果是注册失败,则Intent中包含"error"键对应的值  
  6.        String error = intent.getStringExtra("error");  
  7.        //如果是取消注册,则Intent中包含"unregistered"键对应的值  
  8.        String removed = intent.getStringExtra("unregistered");  
  9.        //打印出接收到的registraton_id,为了调试是查看  
  10.        Log.v(TAG, "handleRegistration");  
  11.        Log.v(TAG, "dmControl: registrationId = " + registrationId +  
  12.                ", error = " + error + ", removed = " + removed);  
  13.        //  
  14.        if(removed != null){  
  15.         //如果存在"unregistered"键对应的值,则表示是取消注册  
  16.         onUnregistrated(context);  
  17.         return;  
  18.        }else if(error != null){  
  19.         //如果存在"error"键对应的值,则表示注册失败  
  20.         onError(context, error);  
  21.         return;  
  22.        }else{  
  23.         //如果以上两种情况都不存在,则表示注册成功了  
  24.         onRegistrated(context, registrationId);  
  25.        }  
  26.          
  27. }  

 

     通过获取注册后返回的Intent中数据,来判断是注册失败(error键值存储的内容不为空)、取消注册(unregistered键值存储的内容不为空)还是注册成功(registration_id键值存储的内容不为空)。

    当是取消注册时,调用onUnregistrated方法进行处理:

  1. //取消注册后的处理函数  
  2. private void onUnregistrated(Context context){  
  3.     Log.v(TAG, "C2DMReceiver Unregister");  
  4.     //取消注册的话,同时也清除保存着的registrationId值  
  5.     C2DMRegistration.clearRegistrationId(context);  
  6. }  

    主要就是清除之前保存在本地的registrationId值

    当是注册失败时,调用onError方法进行处理:

  1. //出错的处理函数  
  2. private void onError(Context context, String errorId){  
  3.     Log.v(TAG, "C2DMReceiver Error with the reason: " + errorId);  
  4.     //首先清除保存着的registrationId值  
  5.     C2DMRegistration.clearRegistrationId(context);  
  6.     //判断出错的原因,一共有六种原因:SERVICE_NOT_AVAILABLE,ACCOUNT_MISSING,AUTHENTICATION_FAILED,  
  7.     //TOO_MANY_REGISTRATIONS,INVALID_SENDER,PHONE_REGISTRATION_ERROR  
  8.     if("SERVICE_NOT_AVAILABLE".equals(errorId)){  
  9.         //只有SERVICE_NOT_AVAILABLE这个是C2DM服务器没有响应的原因,可以等待一段时间后重新发送注册请求  
  10.         //其他原因都是属于客户端设备没有处理好的原因  
  11.         long backoffTimeMs = C2DMRegistration.getBackoff(context);  
  12.         Intent retryIntent = new Intent("com.google.android.c2dm.intent.RETRY");  
  13.         PendingIntent retryPIntent = PendingIntent.getBroadcast(context,   
  14.                    0 /*requestCode*/, retryIntent, 0 /*flags*/);  
  15.            AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);  
  16.            am.set(AlarmManager.ELAPSED_REALTIME,  
  17.                    backoffTimeMs, retryPIntent);  
  18.            // 下一次重试时等待更长的时间  
  19.            backoffTimeMs *= 2;  
  20.            C2DMRegistration.setBackoff(context, backoffTimeMs);  
  21.     }  
  22.       
  23.       
  24. }  

    如果是注册失败,可以从Intent中获取”error”键值对应数据,根据这个数据值可以查看失败的原因。失败的原因有:

    1. SERVICE_NOT_AVAILABLE:Google的服务器未响应。客户端程序可以等待一段时间重新尝试。

    2. ACCOUNT_MISSING:Android设备上缺少Google账户。在Android设备上登录一个Google账户后再重新尝试。

    3. INVALID_SENDER:Sender ID邮箱C2DM服务器不认识。这个需要把Sender ID邮箱号在C2DM网页上进行注册。

    4. PHONE_REGISTRATION_ERROR:当前Android设备不支持C2DM服务。使用2.2及以上版本Android系统来重新尝试。

    除了以上四个常见的原因外还有AUTHENTICATION_FAILED和TOO_MANY_REGISTRATIONS原因。

    SERVICE_NOT_AVAILABLE是C2DM服务器临时没有响应,可以在代码中进行重新尝试注册。其他都是设备端的原因,都不是可以在代码中解决的。

    注册的回调中除了以上两个结果外,就是注册成功返回registration_id的结果了,调用onRegistrated方法:

  1. //注册成功后的处理函数  
  2. private void onRegistrated(Context context, String registrationId){  
  3.     Log.v(TAG, "C2DMReceiver Register with the registrationId = " + registrationId);  
  4.     //注册成功的话,保存获取的registrationId值  
  5.     C2DMRegistration.setRegistraionID(context, registrationId);  
  6.     //然后把registrationId值发送给我们自己的第三方服务器  
  7. }  

    注册成功后可以把registration_id值保存在本地。同时重要的是还要发送给我们自己的第三方服务器。发送的方式可以使用HTTP POST的方式等。当把registration_id值发送给了第三方服务器后,完整的注册过程才算完成,之后第三方服务器就可以使用这个registration_id来给我们的客户端程序推送消息了。

 

     C2DM服务器正式的推送消息也在这个类里进行处理。当接收到推送的消息时,就调用handleMessage方法:

  1. //接收到C2DM推送信息的回调处理  
  2. private void handleMessage(Context context, Intent intent){  
  3.     onMessage(context, intent);  
  4. }  

在这个方法里调用了onMessage回调方法:

  1.     //接收到推送消息后的处理函数  
  2.     private void onMessage(Context context, Intent intent){  
  3.         Log.v(TAG, "C2DMReceiver Message");  
  4.         Bundle extras = intent.getExtras();  
  5.         if(extras!=null){  
  6.             //根据键值,提取对应的消息内容  
  7.             String msg = (String)extras.get(AndroidC2DMDemo.MESSAGE_KEY_ONE);  
  8.             Log.v(TAG, "The received msg = "+msg);  
  9. //          //在标题栏上显示通知  
  10.             NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);  
  11.             Notification notification = new Notification(R.drawable.icon, msg, System.currentTimeMillis());  
  12.             PendingIntent contentIntent = PendingIntent.getActivity(context, 0new Intent(context, AndroidC2DMDemo.class), 0);  
  13.             notification.setLatestEventInfo(context, context.getString(R.string.app_name), msg, contentIntent);  
  14.             notificationManager.notify(0, notification);              
  15.         }  
  16.     }  

    前面说过,Android设备接收推送消息有三个步骤,不过前两步都已经在Android2.2及之后的系统中处理,我们的客户端程序只要处理第三步:即从com.google.android.c2dm.intent.RECEIVE Intent中提取键值对数据。键值是应该和第三方服务器端商量好的。获取键值对应的数据方式很简单。为了方便查看,下面的代码是把获取的数据在通知栏处显示出来。

    处理C2DM数据的C2DMReceiver的完整代码为:

  1. public class C2DMReceiver extends BroadcastReceiver{  
  2.     //  
  3.     private static final String TAG="C2DMReceiver";  
  4.     //  
  5.     @Override  
  6.     public void onReceive(Context context, Intent intent) {  
  7.         // TODO Auto-generated method stub  
  8.         if(intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")){  
  9.             //如果是注册返回的Intent  
  10.             handleRegistration(context, intent);  
  11.         }else if(intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")){  
  12.             //如果是接收到C2DM推送消息的Intent  
  13.             handleMessage(context, intent);  
  14.         }  
  15.     }  
  16.     //注册后的回调处理  
  17.     private void handleRegistration(final Context context, Intent intent){  
  18.         //如果是注册成功,则Intent中包含"registration_id"键对应的值  
  19.         final String registrationId = intent.getStringExtra("registration_id");  
  20.         //如果是注册失败,则Intent中包含"error"键对应的值  
  21.         String error = intent.getStringExtra("error");  
  22.         //如果是取消注册,则Intent中包含"unregistered"键对应的值  
  23.         String removed = intent.getStringExtra("unregistered");  
  24.         //打印出接收到的registraton_id,为了调试是查看  
  25.         Log.v(TAG, "handleRegistration");  
  26.         Log.v(TAG, "dmControl: registrationId = " + registrationId +  
  27.                 ", error = " + error + ", removed = " + removed);  
  28.         //  
  29.         if(removed != null){  
  30.             //如果存在"unregistered"键对应的值,则表示是取消注册  
  31.             onUnregistrated(context);  
  32.             return;  
  33.         }else if(error != null){  
  34.             //如果存在"error"键对应的值,则表示注册失败  
  35.             onError(context, error);  
  36.             return;  
  37.         }else{  
  38.             //如果以上两种情况都不存在,则表示注册成功了  
  39.             onRegistrated(context, registrationId);  
  40.         }  
  41.           
  42.     }  
  43.     //接收到C2DM推送信息的回调处理  
  44.     private void handleMessage(Context context, Intent intent){  
  45.         onMessage(context, intent);  
  46.     }  
  47.     //和C2DM推送信息相关的具体处理函数  
  48.     //注册成功后的处理函数  
  49.     private void onRegistrated(Context context, String registrationId){  
  50.         Log.v(TAG, "C2DMReceiver Register with the registrationId = " + registrationId);  
  51.         //注册成功的话,保存获取的registrationId值  
  52.         C2DMRegistration.setRegistraionID(context, registrationId);  
  53.         //然后把registrationId值发送给我们自己的第三方服务器  
  54.     }  
  55.     //取消注册后的处理函数  
  56.     private void onUnregistrated(Context context){  
  57.         Log.v(TAG, "C2DMReceiver Unregister");  
  58.         //取消注册的话,同时也清除保存着的registrationId值  
  59.         C2DMRegistration.clearRegistrationId(context);  
  60.     }  
  61.     //出错的处理函数  
  62.     private void onError(Context context, String errorId){  
  63.         Log.v(TAG, "C2DMReceiver Error with the reason: " + errorId);  
  64.         //首先清除保存着的registrationId值  
  65.         C2DMRegistration.clearRegistrationId(context);  
  66.         //判断出错的原因,一共有六种原因:SERVICE_NOT_AVAILABLE,ACCOUNT_MISSING,AUTHENTICATION_FAILED,  
  67.         //TOO_MANY_REGISTRATIONS,INVALID_SENDER,PHONE_REGISTRATION_ERROR  
  68.         if("SERVICE_NOT_AVAILABLE".equals(errorId)){  
  69.             //只有SERVICE_NOT_AVAILABLE这个是C2DM服务器没有响应的原因,可以等待一段时间后重新发送注册请求  
  70.             //其他原因都是属于客户端设备没有处理好的原因  
  71.         }  
  72.           
  73.           
  74.     }  
  75.     //接收到推送消息后的处理函数  
  76.     private void onMessage(Context context, Intent intent){  
  77.         Log.v(TAG, "C2DMReceiver Message");  
  78.         Bundle extras = intent.getExtras();  
  79.         if(extras!=null){  
  80.             //根据键值,提取对应的消息内容  
  81.             String msg = (String)extras.get(AndroidC2DMDemo.MESSAGE_KEY_ONE);  
  82.             Log.v(TAG, "The received msg = "+msg);  
  83. //          //在标题栏上显示通知  
  84.             NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);  
  85.             Notification notification = new Notification(R.drawable.icon, msg, System.currentTimeMillis());  
  86.             PendingIntent contentIntent = PendingIntent.getActivity(context, 0new Intent(context, AndroidC2DMDemo.class), 0);  
  87.             notification.setLatestEventInfo(context, context.getString(R.string.app_name), msg, contentIntent);  
  88.             notificationManager.notify(0, notification);              
  89.         }  
  90.     }  
  91. }  

    主要就是处理了向C2DM注册后的数据和正式推送数据的接收。在实际使用中,需要添加向我们自己的服务器发送registration_id值。

    然后还需要在AndroidC2DMDemo中启动向C2DM服务器注册:

  1. public class AndroidC2DMDemo extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     private static final String TAG = "AndroidC2DMDemo";  
  4.     public static final String SENDER_ID = "android.c2dm.demo@gmail.com"//使用C2DM服务的用户账户  
  5.     public static final String MESSAGE_KEY_ONE = "msg";   //和服务器商量好的接收消息的键值key  
  6.     //  
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.main);  
  11.         //  
  12.         Log.v(TAG, "Start");  
  13.         if(C2DMRegistration.getRegistrationID(this).equals("")){  
  14.             //如果本地没有保存registration_id值,则向C2DM服务器注册  
  15.             Log.v(TAG, "Register C2DM");  
  16.             C2DMRegistration.register(this, SENDER_ID);  
  17.         }else{  
  18.             //否则说明已经向C2DM服务器注册过了  
  19.             Log.v(TAG, "C2DM registered");  
  20.         }  
  21.     }      
  22. }  

 

    完成了Java代码部分,最后还要在Manifest.xml文件中声明和C2DM相关的权限等信息。

    为了使用C2DM特性,Manifest.xml需要包含以下几个部分:

    1.  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    这个说明程序有注册和接收C2DM消息的权限

    2.  <uses-permission android:name="android.permission.INTERNET" />

    这个在向第三方服务器发送registration_id值时需要使用

    3.  设置和声明一个这样的权限:程序的包名 + ".permission.C2D_MESSAGE,如:   <permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"

       android:protectionLevel="signature"></permission>

<uses-permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"/>

    这表明只有这个应用才能接收到对应Push的消息及注册时返回的结果。

    4.  包含com.google.android.c2dm.intent.RECEIVE 和 com.google.android.c2dm.intent.REGISTRATION这两个Action的接收器Receiver,并且类别设置为程序的包名,同时还需要有com.google.android.c2dm.SEND这个权限,如:

        <receiver android:name=".C2DMReceiver"

                 android:permission="com.google.android.c2dm.permission.SEND">

            <!-- 可以接收实际的Push数据 -->

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

                <category android:name="com.ichliebephone.c2dm" />

            </intent-filter>

            <!-- 可以接收注册后返回的registration_id -->

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

                <category android:name="com.ichliebephone.c2dm" />

            </intent-filter>

        </receiver>

    这表明这个程序能给接收到C2DM服务器发送的数据

    5.  最后还要设置最小SDK版本为8:<uses-sdk android:minSdkVersion="8" />

    完整的Manifest.xml文件为:

 

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.ichliebephone.c2dm"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <uses-sdk android:minSdkVersion="8" />  
  7.     <!-- 设置一个权限,使只有这个应用才能接收到对应Push的消息及注册时返回的结果  -->  
  8.     <permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"  
  9.         android:protectionLevel="signature"></permission>  
  10.     <uses-permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"/>  
  11.     <!-- 设置注册和接收C2DM Push消息的权限 -->  
  12.     <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />  
  13.     <!-- 设置联网权限,在把registration_id发送给服务器的时候要用 -->  
  14.     <uses-permission android:name="android.permission.INTERNET" />  
  15.       
  16.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  17.         <activity android:name=".AndroidC2DMDemo"  
  18.                   android:label="@string/app_name">  
  19.             <intent-filter>  
  20.                 <action android:name="android.intent.action.MAIN" />  
  21.                 <category android:name="android.intent.category.LAUNCHER" />  
  22.             </intent-filter>  
  23.         </activity>  
  24.   
  25.         <!-- 这个程序能给接收到谷歌C2DM服务器发送的数据,并声明对应的权限 -->  
  26.         <receiver android:name=".C2DMReceiver"  
  27.                   android:permission="com.google.android.c2dm.permission.SEND">  
  28.             <!-- 可以接收实际的Push数据 -->  
  29.             <intent-filter>  
  30.                 <action android:name="com.google.android.c2dm.intent.RECEIVE" />  
  31.                 <category android:name="com.ichliebephone.c2dm" />  
  32.             </intent-filter>  
  33.             <!-- 可以接收注册后返回的registration_id -->  
  34.             <intent-filter>  
  35.                 <action android:name="com.google.android.c2dm.intent.REGISTRATION" />  
  36.                 <category android:name="com.ichliebephone.c2dm" />  
  37.             </intent-filter>  
  38.         </receiver>  
  39.           
  40.     </application>  
  41. </manifest>  

 

    完整的工程目录为:

图1 工程目录

    最后创建带有Google API的Android2.2版本及以上的AVD,启动模拟器,在Accounts & Sync中添加账户,就可以运行程序了。

    和前一部分的测试方法类似,运行程序后,会在DDMS中看到获取的registrationId值:

图2 获取的registrationId值

    然后使用获取的registrationId值利用curl命令模拟第三方服务器向C2DM服务器发送要推送的信息:

图3 使用curl向C2DM服务器发送推送信息

    然后一会我们就可以在DDMS中看到客户端程序收到的推送数据:

图4 获取到的推送数据

    同时Android模拟器中也会在通知栏上显示接收到的推送数据:

图5 模拟器接收到的推送数据

    通过测试结果可知,我们实现了Android的C2DM推送功能。

四. 总结

    以上我们简单介绍了Android的C2DM推送功能实现过程中,在Android设备上的客户端部分需要实现的内容,及实际的实现过程。不过因为只是用来说明实现过程,因此代码写的尽量简单,并且为了更容易查看,把各种常量字符串等也直接写在代码中了。如果在实际使用中,可以参考Google的C2DM例子Chrome To Phone中的代码,只要包含其com.google.android.c2dm包中的三个文件,并且新建一个扩展C2DMBaseReceiver的子类来处理注册消息和推送消息的回调即可,其代码更加茁壮。不过通过以上的介绍说明,我们应该可以更好的理解C2DM客户端部分的实现了。

    以后我们继续学习下C2DM服务器部分的实现。

   文章对应的完整代码例子下载地址:

    http://download.csdn.net/source/3462743

分享到:
评论

相关推荐

    AndroidC2DMDemo--客户端代码开发

    总之,Android C2DM客户端开发涉及了应用的注册、接收和处理推送消息等关键步骤。通过理解这些概念并参考提供的`AndroidC2DMDemo`源码,开发者可以实现自己的C2DM服务,为Android应用添加实时推送功能。不过,需要...

    android C2DM基本原理浅析

    Android C2DM 从服务器端将数据push到客户端

    C2DMMessageServer--服务器端代码开发

    【C2DMMessageServer——服务器端代码开发】 这篇文章主要探讨的是如何开发一个基于Google的Cloud to Device Messaging(C2DM)服务的服务器端程序。C2DM是Android平台早期的一种推送通知服务,允许服务器向注册的...

    android c2dm云推送总结

    ### Android C2DM 云推送技术总结 #### 一、C2DM 介绍与背景 C2DM(Cloud to Device Messaging)是Google为Android设备提供的一种推送服务,它允许开发者向用户的应用程序发送数据消息。这项服务使得应用程序能够...

    Android中关于C2DM开发的一点总结

    总之,C2DM在Android开发中的应用涉及到客户端和服务端的集成,以及对推送消息生命周期的理解和管理。开发者需要考虑如何有效地利用这种服务来提高用户体验,同时注意资源使用和安全性。随着技术的发展,现在更多的...

    C2DM Framework.pdf

    简而言之,C2DM框架为Android设备与服务器之间的通信提供了一个间接且可靠的通道,它允许开发者发送消息到客户端设备,即使客户端应用程序并没有运行。这使得推送消息变得更加高效,同时减轻了客户端设备的负担,...

    基于Android云计算消息框架_C2DM_省略_的FoxNews_MID手持移

    1. **Android C2DM集成**:系统利用Android C2DM服务进行信息推送,这涉及到在客户端注册C2DM服务、处理C2DM消息以及实现消息的可靠传输等技术细节。 2. **Web技术客户管理**:中心管理系统采用Web技术进行客户管理...

    C2DM (Android Cloud to Device Messaging)

    Android Cloud to Device Messaging (C2DM) 是一种由谷歌提供的服务,用于支持开发者从服务器向运行Android操作系统的设备发送数据。C2DM旨在为应用程序提供一个简单、轻量级的通信机制,允许服务器通知客户端有新...

    Google第二代云推送服务GCM VS C2DM.pdf

    - **专为Android设计**:C2DM仅支持Android平台,不支持其他操作系统。 - **数据包大小限制**:单个消息的最大大小为512字节。 - **有限的API支持**:提供的API相对较少,对于复杂的推送需求可能不够用。 - **依赖于...

    AndroidC2DMDemo

    `AndroidC2DMDemo`项目是一个用于学习和实践Android推送通知服务的示例,它展示了如何使用C2DM进行设备注册、消息发送和接收的全过程。尽管C2DM已经过时,但理解其工作原理对于掌握GCM和FCM仍然是有益的。在实际开发...

    android 推送

    ### Android C2DM 云端推送服务详解 #### 一、基础知识与重要性 在移动应用开发过程中,特别是在Android平台上,为了使应用能够实时地获取服务器端的最新信息,开发者通常面临两种选择:Pull(拉取)和Push(推送...

    推送通知推送通知推送通知

    C2DM已经被Firebase Cloud Messaging (FCM)所取代,但为了了解历史背景和理解现有的代码库,理解C2DM仍然是有益的。 在Java-C2DM-master这个项目中,我们可以看到以下几个关键部分: 1. **注册过程**:Android设备...

    Android代码-c2dm-android-pilot

    This is a very simple android application to test out the new C2DM feature from Google. The code is open source and free to use and abuse. The simplest way to build and install the application is to ...

    Android推送服务的应用开发.pdf

    在Android系统中,Google提供了Cloud to Device Messaging(C2DM)服务,它是一个帮助开发者从服务器向Android应用程序发送数据的平台。C2DM服务简化了服务器与移动应用之间的通信,允许服务器向设备发送应用程序...

    微信ANDROID客户端架构演进及其对开发流程的影响.pdf

    ### 微信ANDROID客户端架构演进及其对开发流程的影响 #### 概述 随着移动互联网技术的迅猛发展,微信作为一款国民级应用,其ANDROID客户端的架构经历了多次重大的变革与优化。这些变革不仅反映了软件工程实践中...

    Android消息推送之GCM客户端完整实现

    在Android应用开发中,消息推送是一项重要的功能,它能让服务器实时地向客户端发送通知或数据,而无需客户端主动请求。Google Cloud Messaging(GCM)是Google提供的一项免费服务,用于在Android设备和服务器之间...

    数据结构C2B2B语言描述——应用标准模板库STL第2版源代码

    标题“数据结构C2B2B语言描述——应用标准模板库STL第2版源代码”暗示了这个压缩包包含了基于C++(C2B2B可能是指C++的某种特定风格或应用场景)的数据结构实现,特别是使用了STL的第二版设计和实现。源代码通常意味...

    Android新浪微博客户端

    Android新浪微博客户端是一款基于Android操作系统开发的应用程序,允许用户在移动设备上浏览、发布、分享微博,与其他用户进行互动。该客户端在2011年5月12日进行了更新,可能包含了当时的最新功能和优化,旨在提供...

    软件体系结构 C2风格文件管理 源代码

    通过对"软件体系结构 C2风格文件管理 源代码"的分析和学习,开发者可以了解如何设计和实现一个高效、可靠的文件管理系统,同时也能掌握模块化和分层设计的实践方法,这对于提升软件工程能力非常有帮助。在实际工作中...

Global site tag (gtag.js) - Google Analytics