背景
从 Android 9(API 级别 28)开始,Android 平台对应用能使用的非 SDK 接口实施了限制,只要应用引用非 SDK 接口或尝试使用反射或 JNI 来获取其句柄,这些限制就适用,这些限制旨在帮助提升用户体验和开发者体验,为用户降低应用发生崩溃的风险,同时为开发者降低紧急发布的风险。
区分 SDK 接口和非 SDK 接口
一般而言,公共 SDK 接口是在 Android 框架软件包索引中记录的那些接口,非 SDK 接口的处理是 API 抽象出来的实现细节,因此这些接口可能会在不另行通知的情况下随时发生更改。
为了避免发生崩溃和意外行为,应用应仅使用 SDK 中经过正式记录的类,这也意味着当您的应用通过反射等机制与类互动时,不应访问 SDK 中未列出的方法或字段。
非 SDK API 名单
为最大程度地降低非 SDK 使用限制对开发工作流的影响,Google 将非 SDK 接口分成了几个名单,这些名单界定了非 SDK 接口使用限制的严格程度(取决于应用的目标 API 级别):
- greylist 无限制,可以正常使用
- blacklist 无论什么版本的手机系统,使用这些api,系统将会抛出异常
- greylist-max-o 受限制的灰名单,APP运行在 版本<=8.0的系统里 可以正常访问,targetSDK>8.0且运行在>8.0的手机会抛出异常
- greylist-max-p 受限制的灰名单,APP运行在 版本<=9.0的系统里 可以正常访问,targetSDK>9.0且运行在>9.0的手机会抛出异常
- greylist-max-q 受限制的灰名单,受限制的灰名单。APP运行在 版本<=10.0的系统里 可以正常访问,targetSDK>10.0且运行在>10.0的手机会抛出异常
测试你的应用是否使用了非 SDK 接口
这里我们通过veridex工具进行测试,veridex 工具会扫描 APK 的整个代码库(包括所有第三方库),并报告发现的所有使用非 SDK 接口的行为。
不过veridex 工具存在以下局限性:
- 它无法检测到通过 JNI 实现的调用
- 它只能检测到一部分通过反射实现的调用
- 它对非活动代码路径的分析仅限于 API 级别的检查
- 它只能在支持 SSE4.2 和 POPCNT 指令的机器上运行
我们以Mac系统为例,首先我们需要下载veridex 工具:
https://android.googlesource.com/platform/prebuilts/runtime/+archive/master/appcompat.tar.gz
然后解压缩 appcompat.tar.gz 文件的内容,在解压缩的文件夹中,找到 veridex-mac.zip 文件并将其解压缩,转到解压缩的文件夹,然后运行下面的命令,其中 /path-from-root/your-app.apk 是你要测试的 APK 的路径,从系统的根目录开始:
./appcompat.sh --dex-file=/path-from-root/your-app.apk
文件夹中的hiddenapi-flags.csv文件是需要根据targetAPI版本来更新的,不同的版本会有不同的检查清单,具体可参考:
https://developer.android.google.cn/distribute/best-practices/develop/restrictions-non-sdk-interfaces#determine-list
报告
生成的报告如下图,我们主要关注红框部分的内容就可以了,如果存在blacklist的接口一定是需要修复的: