去年弄了一波Android15的适配,由于事先没做啥准备,所以做的也是比较匆忙,比较被动,导致某些特性没有被适配就把app发布出去了,结果当然是反复被pua,没办法,活干的不到位嘛,牛马就要有牛马的觉悟,现在到了新的一年了,按照谷歌的惯例,今年估计要轮到Android16了,妥妥的新的一波OKR在向我招手,那么咱先看看这个Android16里面有啥东西值得我们去注意的
JobScheduler配额优化
JobScheduler的配额是指应用在一定时间内可以执行的job数量,而从Android16开始,JobScheduler的配额会根据以下三个元素而发生改变
- 应用所处的待机存储分区(standby bucket):活跃的待机存储分区的应用将开始通过宽松的运行时配合强制执行
- 如果作业在应用处于前台状态时开始执行:如果作业在应用对用户可见时开始执行,并在应用变为不可见后继续执行,则会遵守作业运行时配额
如果想要取消这种设置,可以执行以下adb命令
bash
adb shell am compat enable OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS APP_PACKAGE_NAME
- 如果作业在运行前台服务时执行:与前台服务同时执行的作业将遵守作业运行时配额
如果想要取消这种设置,可以执行以下adb命令
bash
adb shell am compat enable OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS APP_PACKAGE_NAME
有的人可能不知道什么是待机存储分区,可以这么理解,系统会给所有应用安排了五个分区,系统会根据每个应用最近什么时候使用以及使用频率来分配至各个分区,有点像读书时候学校给我们分班,学习好的分到重点班,学习一般的分到普通班,不同分区的应用收到的系统的限制也就不一样,比如活跃区的应用的作业,可以相对获得更好更多的运行资源,相当于重点班的学生,得到的师资水平肯定都是最好的,那么如何知道当前自己的应用处于哪个分区呢,可以使用以下adb命令
js
adb shell am get-standby-bucket APP_PACKAGE_NAME

如果得到结果是10就说明你的应用处于活跃区,不受系统限制,任何大于10的数字,都说明你的应用会被系统限制,或者你想要看看你的应用处于某个分区会有哪些行为,那么可以尝试如下命令
arduino
adb shell am set-standby-bucket APP_PACKAGE_NAME active|working_set|frequent|rare|restricted

新的作业停止原因
在Android16之前,如果想要知道作业停止的原因,为什么会产生废弃作业,就必须去监听STOP_REASON_TIMEOUT这个字段,而在Android16中,这个字段被废弃了,改为STOP_REASON_TIMEOUT_ABANDONED,相关应用需要为此做相应适配

有序广播的优先级范围
如果想要给应用中的若干广播设置个优先级,用来给广播接收器接收和处理消息有个先后顺序,通常要么是在清单文件中静态设置android:priority,要么就是在代码中动态设置IntentFilter.setPriority,这样能保证无论你的应用是单进程还是多进程,接收器都能按照顺序接收处理消息,但是Android16里面将这个优先级范围改了,改成这个优先级只在单进程有效,如果是多进程,将无法保证广播接收器执行和接收消息的先后顺序
另外非系统组件的优先级区间只能在(SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1)区间内,只有系统组件才可以设置SYSTEM_LOW_PRIORITY,SYSTEM_HIGH_PRIORITY
16 KB 页面大小兼容模式
刚对齐完16kb的我还没缓过来,这下又看到这几个字,着实让我眼皮蹦了几下,心想没完啦?不过还好仔细看了看,就是弄了个兼容模式,甚至之前还遇到过只是不知道这原来是Android16里面的feature,兼容模式就是下面这个框子

出现这个框子的前提是你的应用运行在了不低于Android16的设备上并且没有完全对齐16kb,那么会出现这个弹框警告你一下,但是不影响app使用,不管你的target是35还是36都会看到这个弹框,而且如果你不想要让这个弹框出现,可以在AndroidManifest.xml中添加下面这个配置 android:pageSizeCompat="enabled",那么弹框就不会出现了,使用pageSizeCompat必须得将targetSdk升级到36,但虽然官方解释如此,但是我自己尝试下后发现无论将pageSizeCompat设置为enabled还是disabled都无法阻止弹框出现,无论是debug还是release包都尝试了没有任何变化,不知道是不是模拟器的关系,反而使用以下命令是可以的

这俩命令用于强制打开16kb向后兼容模式,当设置完后,再一次启动应用就不会看到那个警告弹框了,第一条命令是控制加载库的方式,第二条命令是用于控制apk的安装方式
预测性返回支持三按钮
Android16里面对预测性返回做了进一步更改,长按返回键可以触发预测性返回动画,支持返回到桌面,任务间切换,activity间切换

防范Intent重定向攻击
什么是Intent重定向
当一个易受攻击的app唤起了一个组件的时候,攻击者会全部或者部分地控制住intent,然后会在受害app的上下文中打开某些隐私操作,或者截取url来获取一些敏感数据,甚至可能盗窃数据
如何防范
target36或以上
使用最新api方法removeLaunchSecurityProtection()来抵御攻击

target35或以下

停用无边框设计的选择退出功能
从这里开始讲的变动都是针对目标平台都指向36的应用,首先看到的是无边框设计,上一篇文章中讲到了应用的目标平台如果指向35后,无边框设计将会默认被开启,需要使用WindowInsets来给应用加上边衬区才可以处理那些被遮挡的问题,但是有一个开关windowOptOutEdgeToEdgeEnforcement如果将它打开,那么系统会自动给你关闭无边框设计功能

我把之前演示过的demo里面的适配代码注释掉,然后将Activity的主题里面加上windowOptOutEdgeToEdgeEnforcement属性并打开,会发现...

果然页面不再被系统栏挡住了,状态栏导航栏也都不是透明的了,居然有这么好的东西!可惜知道的太晚,我已经适配完了,但是这么好的东西,到了Android16就要被废弃了,我们将target指向36看看

看到没,又打回原样了,不过这个也是因为我跑的模拟器平台也是16的,如果换成15的设备,windowOptOutEdgeToEdgeEnforcement这个开关依然能用,所以还是不要偷懒了,都去适配吧
预测性返回迁移或者暂时停用
预测性返回这个特性是Android15出来特性,但是那会还处于默认停用状态,但是到了Android16,这个预测性返回将会被默认开启,这也就意味着你项目里面类似于onBackPressed方法,以及KeyEvent.KeyCODE_BACK将会变得无效,可以试一下在target指向36的项目中重写一下onBackPressed,就会发现该方法上会有根红线

这里的红线并不会影响编译,但是跑起来后发现点击back按钮,我们的toast就出不来了,明显没有走到onBackPressed方法里去

如果想要继续在onBackPressed方法中回调,那么就要关闭预测性返回,方法就是在AndroidManifest.xml文件中的或者节点下添加如下属性

当加上这个开关后,会发现onBackPressed方法上的红线也消失了,运行后会点击back按钮,界面上也弹出来了toast

有了这个开关,至少能够保证你可以先将你的app的目标平台升至36,等到预测性返回适配完成后,再将开关取消掉,既不会影响上线时间,也不会遇到预测性返回带来的一些功能失效
最后
总的来说,Android16有不少属性或者api被废弃了,如果你的应用之前有用到,那么这里就需要做一些调整,还有就是预测性返回,这次被默认开启了,虽然有个开关可以暂时把它关掉,但估计这个开关被废弃也是迟早的事情,所以没有适配预测性返回的老哥们,也得抓紧开始搞起了