作者简介
Symeon,携程高级移动开发工程师,关注Android前沿技术。
Google Play 商店在 2021 年第 3、4 季度正式加强对应用 targetSdkVersion 的限制,要求应用必须以 API 级别 30 (Android 11) 或更高版本为目标运行环境。
作为第一个强制要求分区存储的 API 级别,Android 11无疑是近几年适配工作较为复杂的版本,各个 APP 的适配进度也被寄予期盼。Trip.com APP 在 2021 年第一季度进行了 Android 11 的适配,本文将从方案设计和技术改造等⻆度,聊一聊我们的实践与感想。
一、背景
1.1 当我们说 “适配” 的时候
假如你在 Android 大版本更新后第一时间升级了仍处在 Beta 阶段的新系统,也许你会发现手机里安装的应用出现了各种奇怪的问题,随着应用更新,闪退等状况才逐渐减少。
从应用的⻆度来看,我们可以把这段时间分为三个阶段,分别是:
“应用什么都不做,直接在新系统上使用” → 此时应用可能会闪退
“应用针对‘面向所有应用的行为变更’做了对应的更新” → 保证了应用的基本功能可以正常运行,并受到新系统版本的少量限制
“应用将 targetSdkVersion 更新至新系统级别” → 能够使用所有新系统特性,并受到新系统版本的完全限制
为了在本篇文章的表述中统一概念、避免翻译和措辞带来误解,下文暂且将这三个阶段称为“未兼容”、“已兼容“、”已适配“。
1.2 Android 11 的特别之处
2019 年的 Google I/O 大会上,Google 演示了 Android 10 的新特性。IMEI(唯一设备标识符)和设备 MAC address(媒体访问控制地址)的访问受到了限制。同时,Android 10 首次正式带来了分区存储 (Scoped storage) 这个期盼已久的功能,但作为一个大型变更,Android 10 的正式版里最后还是留下了一个开关,如果在AndroidManifest.xml文件内设置了android:requestLegacyExternalStorage="true",就相当于关闭了分区存储,仍采用旧版存储模型。
这相当于留下了一个系统版本的缓冲时间,让各个应用可以逐渐迁移。而当 targetSdkVersion 升级到 Android 11 后,分区存储功能会被强制启用。
二、变更要点
2.1 包可见性
适配 Android 11 之前,APP可以获取到手机已安装的应用列表信息。作为一个国际化的产品,用户隐私是我们非常重要的考量范围,所以这个能力仅在极少数场景下会用到,比如在导航前检查是否有安装地图类APP,或是在点击客服电话时唤起拨号APP。
而在 targetSdkVersion 调整之后,当我们调用 getInstalledPackages() 时,获取到的则是空列表。检查单个 APP是否已经安装也无法正确得知结果。
正因为我们谨慎地使用这个能力,所以适配的工作量也不大,要得知某个 APP 是否安装以及触发某种 Intent 时,就需要在 AndroidManifest.xml 文件内配置对应的 Intent 。例如添加部分导航 APP 的包名、加入拨打电话的 Intent 。参考的配置格式如下:
<manifest package="com.example.game">
<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
...
</manifest>
2.2 唯一标识
从 Android 10 开始,Google 限制了对 IMEI 的获取,Android 11 延续了隐私保护的趋势,对其他的有可能作为唯一标识的方法进行了限制,所有不可重置、难以重置的标识符,都会逐步被要求更改为可重置、可变更的标识符。适配 Android 11 后,Mac 地址和 ICCID 的获取都受限了。
2.3 分区存储
在 Android 11 之前的版本,Android 的文件存储可以分成以下几类:
1)内置存储里的应用私有目录
2)外置存储里的应用私有目录
3)外置存储里的媒体文件
4)外置存储里的文件
其中 4 包含了 2 和 3,这里的“包含”指的是,当我们申请了外置存储的读写权限之后,对外置存储内的所有文件都拥有了操作的能力。APP 无需权限就可以读写属于它的应用私有目录,这点在适配 Android 11前后都没有变化。
Android 的存储权限问题一直为人诟病,主要问题在于外置存储里的“媒体”相关权限和“文件”相关权限均被归类在 WRITE_