转载请注明出处:https://lizhaoxuan.github.io
android真的被玩坏了,android界有一场永远停不下来的攻防战,攻和防都流氓
背景
做为用户,你肯定抱怨过手机上有太多杀不死的应用浪费你的内存,浪费内存就算了,他们还跑你的流量。OK,为了提供更好的用户体验,以MIUI为首的神隐模式(因为我只知道MIUI的叫神隐……就先以他为首吧,有了解谁先出的快告诉我),各个系统厂商都推出自己的XX模式。
在手机息屏后,未加入白名单的应用将会被禁止访问网络。
嗯……这个做的好!用户这回开心了呀:-D。(虽然好像有人抱怨神隐有Bug)。
可是开发者哭了啊,老板一定要让我完成这个需求啊,隔段时间上传或获取个数据呀,你给我断网了我咋办?系统级屏蔽的啊这是,我没法搞了啊……联系运营产品公关还有各种大BOSS!
“我们联系下MIUI官方,把我们默认加白名单行不行?”
“先不说MIUI给不给,除了MIUI还有别家系统啊,而且谁都联系都能加白名单,这模式还有啥用”
“让设计做引导页”
“系统真的是太多了啊……同一个系统不同版本还有差别啊……”
(题外话,话说360电脑版,打开USB调试的引导页真心很屌啊,大部分手机不同型号好像都做了。)
完了,你说怎么办吧?
注:息屏后不能访问网络的实质是,系统休眠后,应用唤醒无法访问网络,所以用轮询执行任务的,是不会出现这种现象的,因为轮询不会让系统休眠,似乎问题解决了是吗?哼哼,你就等着被用户卸载吧,电量哗哗往下掉啊!
所以我们这里讨论的是,使用alarmManager做定时任务的情况
解决思路
方案1
提到息屏后访问不了网络,你第一个想到肯定是系统休眠了,这个简单啊,唤醒不就好了么。PowerManager有个啥属性来着?用这个就可以了!!
额~既然这么简单,那还叫问题吗?
事实是,系统是唤醒了,但是网络就是被中断了,同时被中断的还有GPS,还有什么被禁止的就不清楚了,感兴趣的自己试一下。
方案2
OK,默默的“偷”流量是不行了,我们回归本源想想,问题是息屏后~息屏后~息屏后~诶?同时,leader还提供了一个信息,息屏后收不到推送,但是点亮后,推送都过来了。那我们亮屏了试试?
1 : 时刻关注Log日志,在网络请求失败后,我们手动点亮屏幕。结果是: 请求成功了~原来问题在这里。
2 : 可是手动点亮屏幕不是我们的需求啊,怎么才能自动点亮呢?前段时间做新通知点亮屏幕了,用这个试试。try catch 里,当访问失败进入catch时,我们点亮屏幕并重新请求。
点亮代码是这个:
PowerManager pm = (PowerManager) AliveApplication.getContext().getSystemService(
AliveApplication.getContext().POWER_SERVICE);
PowerManager.WakeLock mWakelock = pm.newWakeLock(
PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "target");
mWakelock.acquire();
mWakelock.release();
//记得权限
<uses-permission android:name="android.permission.WAKE_LOCK"/>
没错,还是PowerManager ,但换了一个参数:
PowerManager.SCREEN_DIM_WAKE_LOCK
奇迹发生了,点亮屏幕后,网络请求成功了。看来这条路没错,要是可以在用户不知情的情况下做就好了,PowerManager还有好几个参数,我们换别的试试?
3 : PowerManager的几个参数及解释:
//保持CPU 运转,屏幕和键盘灯有可能是关闭的。
PARTIAL_WAKE_LOCK
//保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_DIM_WAKE_LOCK
//保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK
//保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
FULL_WAKE_LOCK
/**
* 正常唤醒锁实际上并不打开照明。相反,一旦打开他们会一直仍然保持(例如来世user的activity)。
* 当获得wakelock,这个标志会使屏幕或/和键盘立即打开。
* 一个典型的使用就是可以立即看到那些对用户重要的通知。
*/
ACQUIRE_CAUSES_WAKEUP
/**
* 设置了这个标志,当wakelock释放时用户activity计时器会被重置,导致照明持续一段时间。
* 如果你在wacklock条件中循环,这个可以用来减少闪烁
*/
ON_AFTER_RELEASE
结果是令人失望的,似乎只有在屏幕点亮后网络才能恢复。再换个思路试试。
4 : 监听屏幕点亮与关闭广播,在点亮前,先将屏幕亮度调到0,息屏后,再恢复正常。似乎很可行啊!!
最后的结果失败的,所以这里也不放调节屏幕亮度的代码了。
一个有趣的现象,不知道是系统差别还是Android版本差别。
魅族5.0上,可以实现亮度为0点亮,但是息屏后亮度恢复,屏幕又一下亮了。
酷派 4.1 上,点亮屏幕和调整屏幕亮度没有关系,点亮后依然以之前设置亮度为准。
暂时只测试了这两款机器。
到这里,基本上就已经放弃“暗”的方案了。只能“明”着来了。那这样就要考虑用户体验了
保证用户体验下的解决方案
1.监听网络请求失败后做点亮准备。注意是“准备“”,并不是失败后立马点亮,这个太吓人了,手机放那了不停闪来闪去。
2.准备后,先做请求积累,当到一个临界值时,临界值依具体业务需求而定,依然无法请求,再点亮屏幕一次性发送。
3.利用一切可以利用的资源,点亮屏幕的操作并不是只有你的APP会做,监听屏幕点亮广播,在用户手动点亮、其他应用点亮时做网络请求
4.如果你的请求真的很急切,且略有些频繁,可以加入适当掩饰。比如弹一个本地已经缓存好的通知出来。如果通知并不是很重要,息屏后建议自动清除。
5.如果你的需求迫切到,必须定时定点,那么我的建议是向用户坦白,在什么工作情况下,您的屏幕将会自动被点亮。
6.白名单导航页还是要做的,毕竟进了白名单就没有那么多事了。点亮屏幕只是一个缓冲之计。
7.公关也是要的,如果可以直接被系统默认收进白名单皆大欢喜
8.记得区分是当前无网络还是被屏蔽了,如果用户就是没开数据和wifi,你不停的在闪屏幕,不卸载才怪!
9.并不会息屏后立刻断网,还可以活2-3分钟,有时候5-7分钟也是有可能的,所以事情情况并没有那么严峻。
10.无论是Timer还是线程Sleep,都可以保证系统一直在唤醒状态,但强烈不建议这样做,手机时刻保持唤醒状态,是非常非常耗电的!
示例代码
最后,废话说了这么多,直接上Demo代码啦。代码很简单,里面都写好了注释,具体用户体验逻辑还要Developers 自己添加哦~
https://github.com/lizhaoxuan/IamAlive
对了,还要感谢我的Android组Leader本篇文章的最大贡献者 锦洋大哥 ^.^