`

[原创]通过代码及流程图说明Google在Android上的Push机制的实现

阅读更多
声明: 如果您要转载, 请事先征得本人的同意后方可并且请您附上原文链接. 本人保留一切权利. 多谢!

Google从FroYo版本后引入了C2DM (Cloud to Device Messaging)框架:
http://code.google.com/android/c2dm/index.html
Android Cloud to Device Messaging (C2DM) is a service that helps developers send data from servers to their applications on Android devices. The service provides a simple, lightweight mechanism that servers can use to tell mobile applications to contact the server directly, to fetch updated application or user data. The C2DM service handles all aspects of queueing of messages and delivery to the target application running on the target device.

这个C2DM框架实际上就是一种Push机制, 当服务器端有changes(creates/updates/deletes)时, 服务器端立刻会通过Push机制通知客户端, 然后客户端会通过Sync机制从服务器端获取server-side diffs, 同时也会把client-side diffs发送给服务器端. 通过Push机制, 用户可以及时获得服务器端的改动, 因此有更好的用户体验.

注:
1. Push机制的实现有多种, 比如通过SMS, 以及现在介绍的C2DM.
2. Android上的Sync机制这里不做过多介绍. 实际上对应下面介绍的内容Google是把Push机制和Sync机制一起使用的.

那么, C2DM的实现原理是什么呢? XMPP!!! 和Android GTalk Client的协议实现一样, 都是XMPP, 并且用的都是同一个XMPP框架, XMPP Stack的实现用的是开源的Smack. 其实, 在FroYo之前, Google的Push机制直接就是在XMPP上面, 只不过在引入了C2DM后, 变成Push机制在C2DM上面, 然后C2DM在XMPP上面了.

下面, 通过介绍Android上Google Contacts/Calendar如何利用C2DM实现Push机制来进行说明. 说的顺序可能比较乱, 大家慢慢理解, 并且其中的code只是用来帮助大家来进行理解.

1. 在AndroidManifest.xml上declare了一个broadcast receiver和一个对应的service用来接收C2DM发送的通知.
<receiver android:name=".subscribedfeeds.SubscribedFeedsBroadcastReceiver">
	<intent-filter>
		<action android:name="com.google.android.c2dm.intent.RECEIVE" />
		<category android:name="com.google.android.gsf.subscribedfeeds" />
	</intent-filter>
</receiver>
<service android:name=".subscribedfeeds.SubscribedFeedsIntentService" />

Google Sync是通过Atom Feed协议进行的. 这样当Server端有changes后, 会通过C2DM框架发送"com.google.android.c2dm.intent.RECEIVE" action给SubscribedFeedsBroadcastReceiver,  而SubscribedFeedsBroadcastReceiver在onReceive()方法启动SubscribedFeedsIntentService. 其可能的代码为:
public class SubscribedFeedsBroadcastReceiver extends BroadcastReceiver {
  public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
        intent.setClass(context, SubscribedFeedsIntentService.class);
        context.startService(intent);
    }
  }
}


关于"com.google.android.c2dm.intent.RECEIVE" action, 这是C2DM框架定义的标准action, 可以参考C2DM开发文档.


2. C2DM框架什么时候以及如何发送"com.google.android.c2dm.intent.RECEIVE" action.

这里用到的就是XMPP协议扩展. 这里扩展了XMPP的<message> packet, 在其中加入了自定义的elements. 当Google Server有changes后, 会通过XMPP发送<message>给Android上的XMPP client框架,  XMPP client框架会解析<message> packet, 如果发现是关于Google Sync的<message> packet, 则发送"com.google.android.c2dm.intent.RECEIVE" action.
如何接收自定义的XMPP packets呢? 需要首先了解一下Smack的API, 这里不赘述.

2.1 类DataMessageManager
DataMessageManager是一个PacketListener, 当有特定的Packets到达时会调用它的processPacket()方法.
public class DataMessageManager implements PacketListener
{
......
}


2.2 注册DataMessageManager这个PacketListener
PacketTypeFilter filter = new PacketTypeFilter(DataMessage.class);
connection.addPacketListener(this, localPacketTypeFilter);

注意这里的PacketTypeFilter用的是DataMessage, 表示DataMessage这样的XMPP packets才是需要处理的Packets.

2.3 类DataMessage
public class DataMessage extends Message
{
    ......
    private ArrayList<AppData> mAppDataList;
    private String mCategory;
    private boolean mFromTrustedServer = 0;
    private String mPermission;
    private String mToken;
    ......
}

其中override了一个方法:
public String getExtensionsXML() {
    StringBuilder buf = new StringBuilder()
    buf.append("<data").append(" xmlns=\"")append("google:mobile:data").append("\"");
    if (getCategory() != null)
      buf.append(" category=\"").append(getCategory()).append("\"");
    if (getToken() != null)
      buf.append(" token=\"").append(getToken()).append("\"");
    if (getPermission() != null)
      buf.append(" permission=\"").append(getPermission()).append("\"");
    if (this.mFromTrustedServer)
      buf.append(" from-trusted-server=\"true\"");
    buf.append(">");
    int size = getAppDataSize();
    for (int i = 0; i < size; i++) {
        AppData appData = (AppData)this.mAppDataList.get(i);
        buf.append("<app-data key=\"").append(appData.getKey()).append("\" value=\"")
            .append(appData.getValue()).append("\" />");
    }
    
    buf.append("</data>";
    return buf.toString();
}

从这里可以发现, DataMessage对应的是类似下面的XMPP packets:
<message id="zUwxRf4-9" persistent_id="0:1295969265963580%e7a71353002ea1e0" from="google.com" type="headline"><data xmlns="google:mobile:data" category="GSYNC_TICKLE" token="cl_6" from-trusted-server="true"><app-data key="account" value="zhangsan.android@gmail.com" /></data></message>


也就是说, 当Server端有changes需要客户端来sync的时候, 会发送类似与上面的消息给客户端, 这个消息会被DataMessageManager处理.

而在DataMessageManager的processPacket()方法中, 会再做如下判断:
String category= dataMessage.getCategory();
if ("GSYNC_TICKLE".equals(str2))
      category = "com.google.android.gsf.subscribedfeeds";
Intent intent = new Intent("com.google.android.c2dm.intent.RECEIVE");
intent.addCategory(category);
......
context.sendBroadcast(intent);


这个code会认为category为"GSYNC_TICKLE"的XMPP packets才是有关Google Sync的, 并做相应转换.

3. SubscribedFeedsIntentService被启动, 会调用下面的API进行Sync, 后面涉及到的就是Android的Sync机制了, 如果有时间再解释.
ContentResolver.requestSync(......);


大概的时序图为:





  • 大小: 16.1 KB
  • 大小: 3.1 KB
5
5
分享到:
评论
12 楼 langdechuanshuo 2014-07-14  
楼主你用什么工具画出那个图片的,我之前用过一段时间,在华为的时候,但是出来就不记得了。 一直想不起来。能告诉我吗!
11 楼 fajaven 2012-11-03  
C2DM (新的名字叫 GCM)在国内实际上用不了,因为:
1)国内大部分 Android 手机都没有 Google帐号,所以用不了 Google服务
2)国内 Google服务不稳定。

所以,大家一般的选择是:自己用开源项目如 androidpn 搭建整套环境;另一种选择是使用第三方服务。

androidpn开源不成熟,问题还是挺多的。第三方服务方面,目前国内刚出来了一个,叫极光推送 (http://www.jpush.cn),它提供免费的消息推送服务,最快3分钟能够集成跑起来。
10 楼 fajaven 2012-11-03  
JavaLaDeng 写道
这个必须要smack包吧..??


需要 smack 包是标准的开源方式,比如 androidpn

9 楼 bluceshang 2011-10-20  
AdSFJLSDGH
8 楼 bluceshang 2011-10-20  
    
7 楼 JavaLaDeng 2011-10-09  
这个必须要smack包吧..??
6 楼 JavaLaDeng 2011-10-09  
楼主可在,能否给一个demo?包括服务端的 772008232@qq.com 谢谢..
5 楼 dengsh2008 2011-02-25  
我也想知道服务器是如何通知手机的,手机又不是一直在上网。
4 楼 ak121077313 2011-02-22  
我只想知道"这样当Server端有changes后, 会通过C2DM框架发送"com.google.android.c2dm.intent.RECEIVE" action" service 是怎么发送给客户端的
3 楼 laiyangdeli 2011-02-10  
zhs2472 写道
不用一直开着吧,貌似是接到命令才启动的Service

service一直开着还是需要的时候再开着, 都无所谓了,根据需要. Service各种情况都能满足的.
2 楼 zhs2472 2011-02-10  
不用一直开着吧,貌似是接到命令才启动的Service
1 楼 yangrunfei 2011-02-10  
,是不是这个服务客户端一直在开着呢,可以关闭不?

相关推荐

    Push机制在Android平台上的实现

    详细介绍了android平台的推送机制,原文是cnki上的,特意打包分享。

    android几种push方式的实现

    附件里有3个压缩包,分别是基于udp,xmpp,wmqtt实现push机制的客户端代码,可以参考http://tokudu.com/post/50024574938/how-to-implement-push-notifications-for-android,哈哈,不过是英文的。

    使用android push notification service 实现即时通知

    使用android push notification service 实现即时通知

    Android push notification 服务端源代码

    Android push notification(即androidpn) 服务端源代码 非bin文件,而是源代码!

    Android wappush讲解

    因此,WAP PUSH实现了短信和WAP业务的结合,节省了您寻找业务的时间,方便您直接找到并使用自己喜 欢的业务。PUSH信息无论是否被用户打开,都会保留在手机 的"推入收件箱"内,用户可以重复打开。  wap push 的意思...

    Android XMPP PUSH 推送手机端、服务端源代码

    Android XMPP PUSH 推送源代码,客户端、服务端实现Android推送,服务端使用tomcat服务器

    android 开发 push 短信协议解析

    android 开发 push 短信协议解析,push短信头,sl,si,co三种push短信的协议解析。用来支持android中mms不支持push短信的缺陷。开发必备

    AndroidPush_ServiceAndClient

    Android Push 服务器和客户端。具体使用方法可参照:http://www.cnblogs.com/hanyonglu/archive/2012/03/16/2399655.html

    水晶报表pull和push方法实现源代码

    水晶报表 pull push 源代码

    Android代码-Push

    To start using it, you need to have set up the Push Server. With the Push Server OK, open the file Config.java and change the addresses of your server and the GCM Sender ID: public static class ...

    Android中WAP PUSH的实现分析

    NULL 博文链接:https://seya.iteye.com/blog/903137

    Android代码-gradle-mvn-push

    gradle-mvn-push See this blog post for more context on this 'library': http://chris.banes.me/2013/08/27/pushing-aars-to-maven-central/. Usage 1. Have a working Gradle build This is upto you. 2. Update...

    Android 短信、WapPush拦截

    一般情况下,使用较标准的Google的android系统,拦截比较成功(例如:摩托罗拉)。 如果手机厂商做了较大的改动,拦截可能会有问题。 例如:联想的乐Phone,魅族M9,等拦截不好。会出现短信进入收件箱,才删除,或者...

    Android第三方PUSH-SDK总结

    Android第三方PUSH-SDK总结。包括小米PUSH

    android push开发

    接下来说说XMPP在android客户端上的应用。分两部分:服务端搭建和客户端实现。 服务端搭建: 点击bin目录下得run.bat,直接搭好服务,在浏览器上输入 http://127.0.0.1:7070 ,可以修改配置在conf/config....

    android Push功能(Channel)

    自己做的一个android Push功能

    Android Server Push - MQTT

    NULL 博文链接:https://fanfq.iteye.com/blog/1405385

    android-push-applications-Google.pdf

    google 给出的 android push 开发指导。 (Building Push Applications for Android)

    android xmpp push实现

    XMPP(可扩展通讯和表示协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。

    Android Push it单机版事件管理APP.zip

    Android Push it单机版事件管理APP是一款个人独立开发的免费android应用,主要应用于日常事务管理,期望能够帮助个人和团队更好地把握时间,让工作和生活更加井井有条。 由于能力和精力有限,完整版的应用可能实现...

Global site tag (gtag.js) - Google Analytics