今天在开发的过程中忽然遇到如下弹窗
纳尼?这是什么鬼?
后续通过搜索资料发现这个是 Android P 引入非SDK接口限制,那哪些是SDK接口,哪些是非SDK接口呢?
区分SDK和非SDK接口
一般来说,公共SDK接口是在Android框架中的那些接口,非SDK接口是自己去看源码发现某些内部方法可以使用,然后通过反射直接调用,但是这个方法是官方更新时可能会进行修改的,而且不会通知你,所以为了保证程序的健壮性,推荐用SDK正式推出的接口。针对非SDK接口官方也有检测工具。
为了最大程度地减少非SDK限制对您的开发工作流的影响,将非SDK接口划分为多个列表,这些列表定义了限制使用它们的严格程度,具体取决于所针对的API级别。下表描述了每个列表:
那触发弹窗的就是里面所说的 greylist
列表,那不同的sdk版本有哪些区别?
确定接口属于哪个列表
Android 10
对于Android 10(API级别29),以下文件描述了所有非SDK接口及其对应的列表:hiddenapi-flags.csv
Android 9
对于Android 9(API级别28),以下文本文件包含不受限制(灰名单)的非SDK API列表:hiddenapi-light-greylist.txt
通过 AOSP
获得该列表
通过使用 AOSP
,你可以生成 hiddenapi-flags.csv
文件,这个文件就包含了所有非sdk接口的列表,那该怎么用?
AOSP
下载地址:https://source.android.com/setup/build/downloading
下载成功之后执行:
m out/soong/hiddenapi/hiddenapi-flags.csv
然后你可以在以下路径看到 hiddenapi-flags.csv
文件
out/soong/hiddenapi/hiddenapi-flags.csv
访问非SDK接口会导致什么问题呢?
如何测试APP中是否包含了受限的非SDK接口?
debug模式下查看 logcat
将应用安装在 Android 9 或者以后的机器上,通过 logcat 查看,会有如下所示的输出:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
利用 StrictMode API
利用 StrictMode 的API也可以测试是否使用了非SDK接口,使用 detectNonSdkApiUsage
方法可以开启这个检测,然后通过 penaltyListener
去监听回调,方法如下:
使用 Veridex
工具进行测试
您还可以使用veridex静态分析工具对APK进行分析。veridex工具会扫描APK的整个代码库,包括任何第三方库,并报告找到的非SDK接口的使用情况。
但是 veridex
工具有它自己的局限性:
- 它无法通过JNI检测调用。
- 它只能通过反射来检测调用的子集。
- 它对无效代码路径的分析仅限于API级别检查。
- 它只能在支持SSE4.2和POPCNT指令的计算机上运行。
1)windows
Windows 没有提供可以直接安装的二进制文件,但是可以通过安装 Linux 子系统(适用于 Linux 的 Windows 子系统),安装参考:https://docs.microsoft.com/en-us/windows/wsl/install-win10
这个安装完成之后就可以到命令行下载 veridex
工具,
下载地址:https://android.googlesource.com/platform/prebuilts/runtime/+archive/master/appcompat.tar.gz
- 下载完成后解压
appcompat.tar.gz
文件 - 在解压文件夹中找出
veridex-linux.zip
并进行解压 - 命令行进入该文件夹并执行如下指令
./appcompat.sh --dex-file=your-app.apk
2)MacOS
- 下载 veridex 工具:https://android.googlesource.com/platform/prebuilts/runtime/+archive/master/appcompat.tar.gz
- 下载完成后解压
appcompat.tar.gz
文件 - 在解压文件夹中找出
veridex-mac.zip
并进行解压 - 命令行进入该目录并执行如下指令
/appcompat.sh --dex-file=/path-from-root/your-app.apk
3)Linux
同Windows中安装完Linux之后的步骤
利用 Android Studio 的 lint 工具
利用 Play Console
其他问题
如何启用对非SDK接口的访问?
您可以通过使用adb命令更改API策略强制启用对开发设备上非SDK接口的访问,您使用的命令因API级别而异,这些命令不需要root用户的设备。
1)Android 10(API级别29)
adb shell settings put global hidden_api_policy 1
还原默认设定
adb shell settings delete global hidden_api_policy
2)Android 9 (API level 28)
adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1
还原设定
adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps
修改API策略中整数含义解释如下:
- 0:禁用所有非SDK接口检测。使用此设置会禁用所有非SDK接口使用的日志消息,并阻止您使用StrictModeAPI测试您的应用。不建议使用此设置。
- 1:启用对所有非SDK接口的访问,但会打印日志消息,并带有警告,说明任何非SDK接口的使用情况。使用此设置还可以使您使用StrictModeAPI测试应用。
- 2:禁止使用属于
blocklist
的非SDK接口或在目标API级别被有条件阻止的非SDK接口。
参考
https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces
https://stackoverflow.com/questions/53864764/detected-problems-with-api-compatibility