1 . 信息:
Android P(禁用非官方API)目前类似的消息此起彼伏,关于国外移动开发者社区 XDA 的活跃者们在 AOSP(Android 开放源代码项目)的代码提交记录中的发现。从 AOSP 最新的 commits 中可以看到,那些使用 Android SDK 里面没有被文档提及的非公开 APIs(也就是使用 @hide 注解标记的 APIs)的 apps 将受到系统限制。
Android P引入了对非官方API的限制。无论是通过反射还是通过JNI等方法, 只要应用程序引用非SDK接口或尝试使用反射或JNI获取其句柄,就会使应用受到这些限制。
禁用非官方API原因
关于为何要减少非官方接口,提高应用稳定性,在2018年2月28日,Google官方有此类声明:原文地址:
https://android-developers.googleblog.com/2018/02/improving-stability-by-reducing-usage.html
Google早在Android N中已经在native层已经对ndk开发所使用的API进行了非官方API接口的限制,目前在Android P中开始实施对java层非官方API(官方SDK接口)的限制。目的是为了确保Android开发者和使用者的稳定性,为减少非官方API带来的崩溃,Google一直在努力着。
02 如何区分官方API和非官方API
官方声明:SDK接口是Android框架中记录的接口。 处理非SDK接口是API抽象化的实现细节; 它可随时更改,恕不另行通知。(官方sdk接口:https://developer.android.com/reference/packages.html)
*结以下几点:*
- Android P预览版暂时对非官方API不做限制,目的是为了提供给开发者用于测试应用中是否使用非官方API。
- Android P预览版暂时会打印使用的非官方API的日志以及弹出相应的toast提供给开发者测试使用(注:Toast是为了增加关注度,logcat中有使用非官方API的详细信息)
- 日志(logcat)信息中包括Android运行时使用的格式的声明类,名称和类型。日志消息还指示访问方式:直接,通过反射或通过JNI。以及适用的灰名单。
*有两种灰名单:*
- light greylisted :包含方法和字段,它们继续在Android P预览版中运行,但Google无法保证在未来版本的平台上访问这些方法和字段。
- dark greylist:开发人员预览版本中无法访问的方法。
这些日志消息可以使用adb logcat访问,并且会显示在正在运行的应用程序的PID下。日志中的条目可能如下所示:
03
使用非官方API的后果
在Developer Preview的后续版本中,访问非SDK接口的各种方法都会产生错误或其他不良结果。
android 10.0 以上HideAPI无法调用
10.0 以上系统提示: Accessing hidden method********* 诸如此类的问题主要是Google 限制了隐藏方法通过反射调用,使用以下代码在,
业务代码调用前先执行可以解决以上问题。
if (SDK_INT < Build.VERSION_CODES.P) {
return;
}
try {
Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
Object sVmRuntime = getRuntime.invoke(null);
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{new String[]{"L"}});
} catch (Throwable e) {
Log.e("[error]", "reflect bootstrap failed:", e);
}