lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

对于非 SDK 接口的限制

Android P 引入了针对非 SDK 接口的使用限制,无论是直接使用还是通过反射或 JNI 间接使用。 无论应用是引用非 SDK 接口还是尝试使用反射或 JNI 获取其句柄,均适用这些限制。 有关此决定的详细信息,请参阅通过减少使用非 SDK 接口提升稳定性

一般来说,应用应当仅使用 SDK 中正式记录的类。 特别是,这意味着,在您通过反射之类的语义来操作某个类时,不应打算访问 SDK 中未列出的函数或字段。

使用此类函数或字段很可能会破坏您的应用。

区分 SDK 接口和非 SDK 接口

一般来说,SDK 接口是指在 Android 框架软件包索引中记录的接口。 对非 SDK 接口的处理是 API 抽象化的实现细节;其会随时更改,恕不另行通知。

Android P 引入了针对非 SDK 接口的新使用限制,无论是直接使用还是通过反射或 JNI 间接使用。 无论应用是引用非 SDK 接口还是尝试使用反射或 JNI 获取其句柄,均适用这些限制。

测试非 SDK 接口

您可以通过下载第一个 Developer Preview (DP1) 版 Android P 来测试您的应用。 DP1 不限制任何非 SDK 接口;而是在应用访问非 SDK 接口时,打印日志并可能发出 Toast 通知。 注意 Toast,它会提醒您注意被建议禁用的接口。 此外,确保检查应用的日志消息,其中包含关于应用所访问的非 SDK 接口的更多详细信息,包括以 Android 运行时所使用的格式列出的声明类、名称和类型。 日志消息还说明了访问方法:直接、通过反射或者通过 JNI。 还包含适用的灰名单。

有两个灰名单:浅灰名单包含在 Android P 中继续工作,但我们不能保证在未来版本的平台中能够继续访问的函数和字段。 如由于某种原因,您不能实现替代列入浅灰名单的 API 的方案,则可以提交错误,以请求重新考虑此限制。

深灰名单包含计划在未来的 Developer Preview 版本中不可访问的函数。

这些日志消息可通过 adb logcat 访问,将出现在正在运行的应用的 PID 项下。 日志中的条目看上去可能类似下面这样:

Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
Accessing hidden method Landroid/app/ActivityThread;->currentActivityThread()Landroid/app/ActivityThread; (dark greylist, reflection)

保留非 SDK 接口的后果

在后续版本的 Developer Preview 中,各种访问非 SDK 接口的方式都会产生错误或者其他不希望的后果。 表 1 详细说明了各种访问方式及其相应的结果。

访问方式 结果
Dalvik 指令引用字段 引发 NoSuchFieldError
Dalvik 指令引用函数 引发 NoSuchMethodError
通过 Class.getDeclaredField() 或 Class.getField() 反射 引发 NoSuchFieldException
通过 Class.getDeclaredMethod() 或 Class.getMethod() 反射 引发 NoSuchMethodException
通过 Class.getDeclaredFields() 或 Class.getFields() 反射 结果中未出现非 SDK 成员
通过 Class.getDeclaredMethods() 或 Class.getMethods() 反射 结果中未出现非 SDK 成员
通过 env->GetFieldID() 调用 JNI 返回 NULL,引发 NoSuchFieldError
通过 env->GetMethodID() 调用 JNI 返回 NULL,引发 NoSuchMethodError