本文共 3861 字,大约阅读时间需要 12 分钟。
推送定义:在任何时间地点服务端向客户端推送一条消息,如果客户端在线或者下次上线,就能接收到该消息。
通常想到的实现方式是:轮询、tcp长连,其目的都是让服务端和客户端之间时刻保持在线状态对于客户端而言,轮询:无非是写个线程按某种配置的时间间隔无限循环去请求服务端是否有新的消息,当有新的消息,就提醒给用户tcp长连:与服务端建立tcp长连,这样服务端就可以直接给客户端发送消息了,当前市面上基本上是以此种方式居多上面两种方式都是比较消耗资源的,而这里我们使用的是另外的一种方式来实现的,如udp无连接:其实现基本原理为,客户端创建socket并向服务端发送udp包,服务端接收到请求连接的udp包之后,将客户端id与ip和端口号进行绑定,当要向某个客户端id发送消息时,找到其对应的ip和端口号,然后将消息组装成udp包发送即可,其大致流程如下:.而对于客户端需要解决的如下几个问题:维护客户端与路由的绑定关系
这里我们需要了解一下NAT,所谓NAT就是,在局域网内部网络中使用内部地址,而当内部节点要与外部网络进行通讯时,就在网关处,将内部地址替换成公用地址,从而在外部公网上正常使用。所以当发送udp包到服务器时,服务器拿到的ip和端口其实是客户端在路由上映射的ip和端口,所以我们需要维护路由上的映射表,这时就需要定期发送心跳包,以保证路由上的映射关系不会被清除掉。app保活是一个老生常谈的话题,经过广大开发者多年累积与筛选,互联网上相关文章层出不穷,目前看来不算什么硬梗,大多都按套路出行,这里也套路套路
当应用退到后台时,为了确保推送通道能够正常使用而不被系统回收,通常会做一些进程保活和拉活的策略,大体分为以下几类:如下两种情况无法拉活:
1.Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。2.进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。经测试,在绝大多数手机任务进程中,手动杀掉进程后,是不会自动重启的(符合情况2)进程按照重要性分为如下5类:
1.前台进程(Foreground process)2.可见进程(Visible process)3.服务进程(Service process)4.后台进程(Background process)5.空进程(Empty process)一般的后台进程进程属于第4类,我们可以通过setForeground将service提升到2,但是这种方案必须与一条可见的通知绑定在一起,而这种体验显然不能被用户接受当然我们可以通过new Notification()的方式设置一个空的通知,与之绑定,但只在4.3以下版本才有效,如下:if (Build.VERSION.SDK_INT < 18) { service.startForeground(1001, new Notification());//API < 18 ,此方法能有效隐藏Notification上的图标}
神奇的开发者们发现了一种通过多实现一个TmpService,在MainService和TmpService两个service中同时发送具有相同 ID 的 Notification,然后干掉TmpService,这时Notification会自动消失,而MainService的优先级已经被提升到2了,从而达到了目的。缺陷是:需要开发者在manifest多配置一个service,可能在不久的将来也会被官方更新掉,不建议采纳。
当然我们可以在代码中添加了相关的系统广播注册、同时在监听进程死掉时发送的广播,测试在某些低版本的手机上有效
IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(Intent.ACTION_USER_PRESENT);intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
但是经测试当系统休眠时,AlarmManager也停止了工作,且在不同sdk版本上需要采用不同的set方式,如下:
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);if (pingPendingIntent != null) { am.cancel(pingPendingIntent);}pingPendingIntent = PendingIntent.getBroadcast(MobSDK.getContext(), 0, new Intent(ALARM_ACTION_PING), PendingIntent.FLAG_UPDATE_CURRENT);final long nextTime = SystemClock.elapsedRealtime() + interval * 1000L;if (Build.VERSION.SDK_INT >= 23) { am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pingPendingIntent);} else if (Build.VERSION.SDK_INT >= 19) { am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pingPendingIntent);} else { am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pingPendingIntent);}``` 5. 进程间相互拉活当某台手机上有多个应用都在使用sdk时,可根据用户在后台配置授权后,选择性的进行相互之间的拉活6. 利用native进程拉活网络中流传的一种利用 Linux 中的 fork 机制创建 Native 进程,在 Native 进程中监控主进程的存活,当主进程挂掉后,在 Native 进程中立即对主进程进行拉活。在 Android 中所有进程和系统组件的生命周期受 ActivityManagerService 的统一管理。而且,通过 Linux 的 fork 机制创建的进程为纯 Linux 进程,其生命周期不受 Android 的管理。这种方案在网上流传已久,听说在5.0以上版本也不成立,且需要额外添加本地代码编译so,无形的添加了app体积,不采纳7. JobScheduler和账号同步机制拉活这种两种方式同样需要在AndroidManifest.xml中注册相关配置和权限,版本限制,效果一般8. 将应用加入厂商或管理软件白名单9. 第三方push通道接入:GSM:国内不支持小米推送、华为推送性能考虑APP性能也是老生常谈的话题,总结其出发点和最终的目的都是为了减少用户流量、内存占用、电量消耗等等方面的优化,以达到省电省流量且界面流畅的终极目标。在开发时,大致可从如下几个方面思考和稍加注意:1. 减少网络请求次数,缩小网络中传输数据的体积,像推送这种主动的操作,可通过自定义数据传输协议来控制流量的消耗
转载地址:http://atiex.baihongyu.com/