最近在搞即时消息推送。了解了推送服务实现的基本原理。通过长连接去实现及时的推送,或者通过轮询的方式去实现伪及时的推送。当然,通常我们选择前者。如果实现长连接就要用到socket,所以简单了解了下socket编程。又因为服务器端需要考虑大并发、性能方面的问题。直接使用socket在性能上无法保证,需要使用java提供的非阻塞式的高伸缩性的网络I/O:nio;因为nio编程比较复杂,开发过程中都是使用现有的框架:MINA或者Netty。我们开发的推送服务是基于AndroidPN这个开源项目实现的。AndroidPn服务器端使用的就是MINA框架。然后又去了解了一下MINA服务器。有了上面的一些理论基础后,就去开开心心的看AndroidPn的源码,修改里面的BUG,去实现自己需要的功能。这里并不去过多的介绍AndroidPn。从上周的工作内容讲起。
推送服务基本实现后,开始着重考虑客户端一直存在的问题。我们都知道要想实现即时的通讯。就必须在客户端和服务器端之间建立一个长连接。而在Android客户端要想维持这个长连接,就要在后台开个单独的进程去维护这个长连接。我的噩梦开始了,用户可以选择随时清空系统内存。或者动不动就按下一键加速什么的。那么我们运行在后台的为了保证及时通信的长连接的服务就会随时被杀掉。大家最常用的办法就是在JNI里面fork出子进程,然后监视 service进程状态,被系统杀死了就重启它。这个办法在5.0之后已经不起作用了。为什么5.0上面就不行了呢,咱们看一下activitymanagerservice,LBE的清理内存应该调用的killBackgroundProcesses,看看他们有什么区别
5.0的代码:
Process.killProcessQuiet(app.pid); Process.killProcessGroup(app.info.uid, app.pid);4.3的代码:
Process.killProcessQuiet(app.pid);
5.0中增加了Group的概念,对同一应用的进程进行统一管理了。当然我们还可以通过一些其他的方式来保证我们的服务长期运行,比如监听系统广播,用户一开机,或者用户手机网络发生变化的时候就去启动我们的服务等等这些“见不得人的”办法。作为有良知的程序员,我们深知这种流氓做法并不可取,但是在需求面前,程序员是没有自己的。不过这种方式效果不尽人意。监听的各种广播在某些ROM比如小米的MIUI,默认是关闭的,需要用户手动打开,哎,至少到目前为止,我还没开发出来能让用户欣喜若狂的选择开机启动、监听各种各样的系统广播的APP ╮(╯▽╰)╭。然后我就想是不是其他开发人员是不是也跟我有同样的烦恼,他们是不是也在想尽办法来让自己的服务能够尽可能长的在后台运行。去网上查了下,这方面的内容很多,提供了各种各样的解决办法,目的也多半都是为了保证服务器可以即时的与客户端进行通讯。为什么Android的手机这么卡,为什么电池会用的那么快。其中一个原因,每个程序都后在后台建立一个长连接,并不断发送心跳包去保证自己的APP可以收到消息。如果你的APP很不巧的集成了不同厂商提供的推送服务。或者链接的自己搭建的推送服务器。那么你要及时清理你的后台应用了,不然会有N多个长连接去不断的发送心跳包,去强奸你的内存、电量、流量,并且没人为此负责。这也是Android手机性能如此强悍,电池容量如此之大,仍然不敌iPhone的原因之一。
那么苹果的是怎么去管理推送的呢。Iphone在系统层建立了一个长连接,去连接你的手机设备和苹果自家的推送服务器APNS(Apple Push NotificaitonService);这个长连接是全局的、独立于每一个APP之外的。应用提供商把消息推送给APNS,APNS借助于系统级的长连接把消息推送给客户端。这样应用本身就不用常驻的后台进程去管理长连接(当然苹果也不允许你这么做)。当苹果把大量的资源开销放在了云端,而非设备上,手机系统开销小了,手机更流畅,电量更耐用。
这是APNS的逻辑所在:IOS系统自己做个长连接。所有应用都必须申请、并且允许才能通过云端服务器把消息通过系统级的长连接发送过来。
这样带来的好处是实实在在的:
① 安全:只有登陆过的开发者可以通过苹果的服务器推送消息。
② 快速、稳定、可靠:苹果自己掌控长连接和推送服务器。
③ 更省电、省内存、省流量
④ 整个系统的体验更加一致和简单。不用考虑杀内存这种脑残事,更不会出现杀内存收不到推送的蛋疼 事。
为什么Android不自己搞个类似的功能呢。其实Android也有,叫GCM(Google Clond Message)。而且在国外很多应用也是用这个服务进行推送的。比如WhatsApp、推特等。但是在国内使用的GCM去推自己消息应该没几家吧。原因:
① GCM作为谷歌的服务经常被墙;
② GCM设置的心跳间隔过长,并不适合国内比较坑的网络环境;
③ 国内的第三方ROM会把GCM阉割掉;
④ 需要绑定Google账号(此要求在Android4.0.4版本后解除)……
总之GCM在国内水土不服。所以Google把GCM做成了可选项。而不是像苹果那样去让第三方开发商强制接入APNS。这个除了因为Android更开放之外,更多的可能是Google的无奈。他们的决策层肯定也清楚的知道让程序员们自己去实现一个服务维护各自应用与推送服务器的长连接会把系统资源搞得乱七八糟的,是各种坑爹的。但是市场环境如此。Google的服务何时能够王者归来,何时不再放纵手机厂商任意阉割google服务,还是个未知数。(借用网友的一张图)
基于以上事实,我们会发现国内各种推送平台应运而生。百度推送、极光推送、友盟推送、信鸽推送、个推…..这些都是GCM的替代品。如果这些推送能够互相残杀,并最终实现一家独大,原理上我们就可以实现APNS那样的效果。因为上面这些推送有些是单通道的。意思就是如果你的手机上的所有应用都使用的百度的推送,实际上这些应用使用的是同一条通道,同一个长连接。跟APNS的原理一致。但事实上是推送市场列国混战,每个厂商身后都有个互联网巨头,每个厂商都用免费去吸引更多的APP接入到自家平台。目的很简单,当用户量足够大的时候就变成了一种隐形的标准。大家都在我这玩。你不来我这,就没法和大家一起玩耍。所以每个厂家都去抢占APP的流量入口。以期在将来的互联网大战中占得先机。所有在想Android端去体验iPhone那样稳定、快速、可靠的推送服务,还遥遥无期。使用第三方推送有些人担心一件事情:他们免费给我们用是为了获取我们的数据,去做数据分析,去搞见不到人的事。我只能说,就你那app的用户量,就你推送的那点数据,你自己都不想做数据分析,也好意思!虽然我不能排除云服务厂商会那样去做。但是因为这个原因去否定云服务,只能说有些顽固不化了。
除了使用第三方的推送服务,也可行自己搞一个出来,正如我们公司现在做的那样,为什么自己要开发一套推送服务呢。主要有几个方面的考虑:
① 我们的数据的的确确不能让外部知道,是绝对的保密的。
② 出于工作环境的考虑,我们的客户端和服务器端都无法与外部链接,是运行在局域网内的。
③ 我们不想受制于人,把权力掌握在自己手里,哪怕能力原因我们受制于自己。
④ 出于工作成果的考虑,相比于花几个小时集成第三方的推送服务,自己搭建一套推送服务,要显 得牛逼的多O(∩_∩)O~。
写在最后:Android的推送服务还是比较坑的,不管是集成第三方还是自己搭建一套推送服务器,都无法实现像APNS那样优雅的推送。使用第三方的推送服务,尤其是使用了市场占有率比较高的推送服务,那么我们推送的到达率相对而言要高些。使用自己搭建的服务器或者使用了比较小众的第三方推送平台,我们在后台维护的那个长连接相比于百度或者腾讯的长连接更容易被杀掉。我们可能同时有几个应用程序都集成了百度的推送,那么集成了百度推送的APP在前台运行的概率就会大一些,维持着长连接的进程更容易存活。我们的APP可以与推送服务器保持更好的连接,正如我们前面提到的,他是单通道的。而自己开发维护的长连接可能并没那么幸运。如果应用程序没有打开,基本是接收不到消息的,除非我们的APP足够流氓,怎么都杀不死。永远在后台运行。搭建一套推送服务器的开发成本,和维护成本对于小企业是很难接受的。对于开发人员:如果有机会自己搭建一套推送服务器,还是很难得的,毕竟很少有企业愿意花大量时间让你研究这个东西。相比于集成第三方的推送服务,自己开发,能让我们对推送的原理、机制有比较深刻的认识,甚至对Android的运行机制有一些新的认识。另外,在一定程度上,也有利于我们去比较和衡量不同推送服务提供商的产品的优劣,做出更合理的选择。
(第一次发文章,好激动,可能有理解不对的地方,求吐槽)