一、前言
最近有个Android项目上需要用到推送机制,所以研究了一下现在主流的推送服务,总结如下:
对于推送功能来说,主要分为PULL和PUSH两种,实际上来说PULL这种思想最为原始,就是通过轮询来向服务器更新自身信息,如今的实现方法基本不会使用。
而PUSH方法,从传统角度来说,是建立SOCKET长连接,然后用特定的协议发送心跳包进行设备状态更新和保持连接时效性。
二、主流方案介绍
目前主流的使用PUSH机制实现的推送有以下几种:
1. C2DM云端推送功能
在Android手机平台上,Google提供了C2DM(Cloudto Device Messaging)服务,起初我就是准备采用这个服务来实现自己手机上的推送功能,并将其带入自己的项目中。
Android Cloud to Device Messaging (C2DM)是一个用来帮助开发者从服务器向Android应用程序发送数据的服务。该服务提供了一个简单的、轻量级的机制,允许服务器可以通知移动应用程序直接与服务器进行通信,以便于从服务器获取应用程序更新和用户数据。C2DM服务负责处理诸如消息排队等事务并向运行于目标设备上的应用程序分发这些消息。关于C2DM具体使用过程,大家可以去查阅相关的资料,在这里先让我们了解下大致方案情况。
但是C2DM这个服务存在很大的问题:
1)C2DM内置于Android的2.2系统上,无法兼容老的1.6到2.1系统;
2)C2DM需要依赖于Google官方提供的C2DM服务器,由于国内的网络环境,这个服务经常不可用,如果想要很好的使用,我们的App Server必须也在国外,这个恐怕不是每个开发者都能够实现的;
3) 不像在iPhone中,他们把硬件系统集成在一块了。所以对于我们开发者来说,如果要在我们的应用程序中使用C2DM的推送功能,因为对于不同的这种硬件厂商平台,比如摩托罗拉、华为、中兴做一个手机,他们可能会把Google的这种服务去掉,尤其像在国内就很多这种,把Google这种原生的服务去掉。买了一些像什么山寨机或者是华为这种国产机,可能Google的服务就没有了。而像在国外出的那些可能会内置。
有了上述几个方面的制约,导致我最终放弃了这个方案,不过我想利用另外一篇文章来详细的介绍C2DM的框架以及客户端和App Server的相应设置方法,可以作为学习资源让我们有个参考的资料。 即然C2DM无法满足我们的要求,那么我们就需要自己来实现Android手机客户端与App Server之间的通信协议,保证在App Server想向指定的Android设备发送消息时,Android设备能够及时的收到。
2.MQTT协议实现Android推送功能(目前最为好用的推送,注:Android的 minSdkVersion 必须<= 9,否则报错)
2.1 IBM的RSMB
采用MQTT协议实现Android推送功能也是一种解决方案。MQTT是一个轻量级的消息发布/订阅协议,它是实现基于手机客户端的消息推送服务器的理想解决方案。
wmqtt.jar 是IBM提供的MQTT协议的实现。我们可以从这里(https://github.com/tokudu/AndroidPushNotificationsDemo)下载该项目的实例代码,并且可以找到一个采用PHP书写的服务器端实现(https://github.com/tokudu/PhpMQTTClient)。
IBM的推送方案是基于自家的RSMB(Really Small Message Broker)实现的,他是一个简单的MQTT代理,同样由IBM提供,其查看地址是:http://www.alphaworks.ibm.com/tech/rsmb。缺省打开1883端口,应用程序当中,它负责接收来自服务器的消息并将其转发给指定的移动设备。
SAM是一个针对MQTT写的PHP库。我们可以从这个http://pecl.php.net/package/sam/download/0.2.0地址下载它.
send_mqtt.php是一个通过POST接收消息并且通过SAM将消息发送给RSMB的PHP脚本。
2.2 基于MQTT的mosquitto
Mosquitto的详细信息可参考下列网址:http://mosquitto.org/
mosquitto是一款开源的推送项目,目前版本趋于稳定
3.XMPP协议实现Android推送功能。
3.1 androidpn推送方案
这是我希望在项目中采用的方案,因为目前它是开源的,对于其简单的推送功能它还是能够实现的。我们可以修改其源代码来适应我们的应用程序。
事实上Google官方的C2DM服务器底层也是采用XMPP协议进行的封装。XMPP(可扩展通讯和表示协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。关于XMPP协议的介绍,可参见http://xmpp.org/。
androidpn是一个基于XMPP协议的java开源Android push notification实现。它包含了完整的客户端和服务器端。经过源代码研究我发现,该服务器端基本是在另外一个开源工程openfire基础上修改实现的,不过比较郁闷的是androidpn的文档是由韩语写的,所以整个研究过程基本都是读源码。
这是androidpn的项目主页:http://sourceforge.net/projects/androidpn/
androidpn实现意图如下图所示:
androidpn 客户端需要用到一个基于java的开源XMPP协议包asmack,这个包同样也是基于openfire下的另外一个开源项目smack,不过我们不需要自己编译,可以直接把androidpn客户端里面的asmack.jar拿来使用。客户端利用asmack中提供的XMPPConnection类与服 务器建立持久连接,并通过该连接进行用户注册和登录认证,同样也是通过这条连接,接收服务器发送的通知。
androidpn服务器端也是java语言实现的,基于openfire开源工程,不过它的Web部分采用的是spring框架,这一点与 openfire是不同的。Androidpn服务器包含两个部分,一个是侦听在5222端口上的XMPP服务,负责与客户端的 XMPPConnection类进行通信,作用是用户注册和身份认证,并发送推送通知消息。另外一部分是Web服务器,采用一个轻量级的HTTP服务器, 负责接收用户的Web请求。服务器架构如下:
最上层包含四个组成部分,分别是SessionManager,Auth Manager,PresenceManager以及Notification Manager。SessionManager负责管理客户端与服务器之间的会话,Auth Manager负责客户端用户认证管理,Presence Manager负责管理客户端用户的登录状态,NotificationManager负责实现服务器向客户端推送消息功能。
这个解决方案的最大优势就是简单,我们不需要象C2DM那样依赖操作系统版本,也不会担心某一天Google服务器不可用。利用XMPP协议我们还可以进一步的对协议进行扩展,实现更为完善的功能。 采用这个方案,我们目前只能发送文字消息,不过对于推送来说一般足够了,因为我们不能指望通过推送得到所有的数据,一般情况下,利用推送只是告诉手机端服务器发生了某些改变,当客户端收到通知以后,应该主动到服务器获取最新的数据,这样才是推送服务的完整实现。 XMPP协议书相对来说还是比较简单的,值得我们进一步研究。
三、方案具体应用
1.RSMB
1.1推送服务端准备
- 下载&解压rsmb安装包(下载地址:http://www.alphaworks.ibm.com/tech/rsmb)
- 进入对应的目录,比如32位的Linux系统则应该进入linux_ia32目录。
- 编辑配置文件broker_1883.cfg,配置如下:
port 1883
max_inflight_messages 10
max_queued_messages 1000
4. 运行./broker broker_1883.cfg
1.2推送客户端准备
- 下载&解压AndroidPushNotificationsDemo项目(下载地址:https://github.com/tokudu/AndroidPushNotificationsDemo)
- 将该项目导入Eclipse中(File -> Export -> Existing Projects into Workspace)
- 修改PushService.java中的MQTT_HOST常量为推送服务端的IP地址。
- 启动Android模拟器,并安装该项目。
1.3 发送服务器准备
- 下载&解压PHP版的发送服务端代码send_mqtt.zip(下载地址:http://download.csdn.net/detail/shagoo/4520102)
- 修改etc/config.php中推送服务端的IP地址和端口号,即MQTT_SERVER_HOST和MQTT_SERVER_POST常量。
- 打开对应的URL地址,就可以看到发送服务的界面,实际上就是向对应的推送客户端推送消息。
2.AndroidPN
2.1准备
首先, 我们需要下载androidpn-client-0.5.0.zip和androidpn-server-0.5.0-bin.zip。
下载地址:http://sourceforge.net/projects/androidpn/ (如果打开不了上面的网址,那就需要翻墙了,你懂得)。
解压两个包,Eclipse导入client,配置好目标平台,打开raw/androidpn.properties文件,配置客户端程序。
2.2 配置
1. 如果是模拟器来运行客户端程序,把xmppHost配置成10.0.2.2[模拟器把10.0.2.2认为是所在主机的地址,127.0.0.1是模拟器 本身的回环地址,10.0.2.1表示网关地址,10.0.2.3表示DNS地址,10.0.2.15表示目标设备的网络地址],关于模拟器的详细信息,大家可参阅相关资料,这里不再详述.
运行客户端,客户端会向服务器发起连接请求,注册成功后,服务器能识别客户端,并维护和客户端的IP长连接。
2. 如果是在同一个局域网内的其他机器的模拟器测试(或者使用同一无线路由器wifi上网的真机) ,则需要把这个值设置为服务器机器的局域网ip.
例如 你的电脑和android手机 都通过同一个无线路由器wifi上网, 电脑的ip地址为 192.168.1.2 而 手机的ip地址为 192.168.1.3, 这个时候 需要把这个值修改为 xmppHost=192.168.1.1 或是电脑的IP地址,就可以在手机上使用了.
3. 如果是不在同一个局域网的真机测试,我们需要将这个值设置为服务器的IP地址。
四、小结