目录
平台
红米k30us
充电+前台
数据线+屏幕常亮
插数据线会改变安卓系统的省电策略。如果要长时间运行,可以考虑保持供电+不锁屏+程序前台运行
websocket保活
由OkHttpClient封装,非官方pro版本。
断开重连
onClose 和 onFailure 触发时重新进行连接,在切换wifi、数据或者服务器服务重启可以第一时间重连。
超时重连
每次接收到心跳包后记录下最后活跃时间,开启一个超时重连检查线程,一旦距离心跳时间过长,重启ws甚至重启程序
心跳保活
采用的客户端服务端结合心跳。
服务端采用php-workman,尝试过服务器和客户端单独发送心跳。
虽然官方推荐客户端定时发送心跳,不建议服务端心跳保活,但在多次测试后选择了2者结合。
效果就是当手机锁屏非充电时,使用服务端保活,其他情况使用客户端保活。
客户端定时发送心跳
锁屏后,日志可以看到我的脚本还在运行,线程也在运行,但是心跳包接收失败。结果就是程序一直重启。
一开始我并没确定是没发出去数据还是没收到数据。
这里发现事实并不是如此,所以注释掉
这里再做解释 autojs websocket后台保活2
直到翻到一篇文章,里面提到。小米手机socket锁屏发包会被吞,等到服务器推送信息过滤才会一次推送上去。
小米手机的神奇Socket
后来又发现客户端只要在后台超过一定时间, 对socket的写操作就会变得非常诡异, 表现为socket把数据吞了, 告知应用数据已经被对方接收, 但是服务器什么都没收到, 而且服务器发送的消息客户端也收不到. 只要让app进到前台, 之前消失的数据会一股脑发给服务器, 客户端会收到服务器重传的消息.
我开始还以为是Android的休眠机制把wifi断了, 我把各种WifiLock, WakeLock都持有了, 还是出这种情况. 后来无意间发现小米针对每个app都有个后台运行时允许联网的开关, 我把它打开了, 果然好了一阵子, 后来又开始重复之前的情况, 我还以为是Mina的IO线程被kill了还是怎么, 用DDMS看了线程信息没问题. 不放心, 又用纯Socket实现了客户端, 还是有问题, 再在之前的基础上加上1分钟的心跳, 还是有问题。
日志示例:
//正常
send clint-ping
rec server-pong
//发包被吞
send clint-ping
send clint-ping
send clint-ping
...
rec server-ping //服务端推送
send clint-pong
rec server-pong
rec server-pong
rec server-pong
...
服务端发送心跳
由于锁屏发包被吞,只能结合使用服务端发送心跳。
具体可以看 workerman-心跳检测
省电策略设置为 无限制
如果没有修改省电策略限制,锁屏后被断网了。
测试记录
设置均不开启
设置 |
状态 |
锁定进程 |
y\x |
自启动 |
y\x |
省电策略 |
x |
插数据线 |
x |
屏幕常亮 |
x |
表现
锁屏后 websocket 连接 直接报错
onFailure java.io.EOFException null
应该是省电策略限制,被断网了
省电策略设置不限制
设置 |
状态 |
锁定进程 |
x |
自启动 |
x |
省电策略 |
无限制 |
插数据线 |
x |
屏幕常亮 |
x |
如果开启自动清理进程,或者手动清除内存,可能会被杀死。
开启前台服务时,自动清理进程不会被杀死
参考资料
Android端消息推送总结:实现原理、心跳保活、遇到的问题等