小米神隐模式破解(反系统息屏后网络中断)

转载请注明出处: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本篇文章的最大贡献者 锦洋大哥 ^.^