今天在开发的过程中忽然遇到如下弹窗

detected_problems_with_api_compatibility

纳尼?这是什么鬼?

后续通过搜索资料发现这个是 Android P 引入非SDK接口限制,那哪些是SDK接口,哪些是非SDK接口呢?

区分SDK和非SDK接口

一般来说,公共SDK接口是在Android框架中的那些接口,非SDK接口是自己去看源码发现某些内部方法可以使用,然后通过反射直接调用,但是这个方法是官方更新时可能会进行修改的,而且不会通知你,所以为了保证程序的健壮性,推荐用SDK正式推出的接口。针对非SDK接口官方也有检测工具。 为了最大程度地减少非SDK限制对您的开发工作流的影响,将非SDK接口划分为多个列表,这些列表定义了限制使用它们的严格程度,具体取决于所针对的API级别。下表描述了每个列表:

non-sdk-cat-list

那触发弹窗的就是里面所说的 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接口会导致什么问题呢?

non-sdk-behavior

如何测试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 去监听回调,方法如下:

penalty-listener

使用 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

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