Android P以上,引入非公开Api的限制,不允许通过反射去获取Method或者Field。
大概原理讲解:blog.csdn.net/yuanjinsong…
建议先看讲解再看下面解决办法
// 公开API,无问题Method metaGetDeclaredMethod = Class.class.getDeclaredMethod("getDeclardMethod");
// 系统类通过反射使用隐藏 API,检查直接通过。Method hiddenMethod = metaGetDeclaredMethod.invoke(hiddenClass,"hiddenMethod", "hiddenMethod参数列表");
// 正确找到 Method 直接反射调用hiddenMethod.invoke
举个具体例子:
在Android P以上,想要获取IActivityManager$Stub里面的这个属性“TRANSACTION_startService“的值,原来是需要这么调的:
Class.forName("android.app.IActivityManager$Stub").getDeclaredField("TRANSACTION_startService");
但是在P以后这么调用会出错,抛出NoSuchFieldException。
解决办法:
Class.class.getDeclaredMethod("getDeclaredField",String.class)
.invoke(Class.forName("android.app.IActivityManager$Stub")
,"TRANSACTION_startService")
上述这种办法只能针对个别被隐藏的Api。若你想要反射的Method或者Field比较多的话,可以采取以下办法,一劳永逸。
public class Reflection {
public static Object vmRuntime;
public static Method setHiddenApiExemptions;
static {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
//参考文章:https://blog.csdn.net/yuanjinsong123/article/details/93209527
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);
setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
vmRuntime = getRuntime.invoke(null);
} catch (Exception e) {
e.printStackTrace();
LogUtils.e("Reflection", "reflect bootstrap failed:", e);
}
}
}
public static boolean exempt(String... methods) {
if (vmRuntime == null || setHiddenApiExemptions == null) {
return false;
}
try {
setHiddenApiExemptions.invoke(vmRuntime, new Object[]{methods});
return true;
} catch (Throwable e) {
return false;
}
}
public static boolean exemptAll() {
return exempt(new String[]{"L"});
}
public static void init() {
if (Build.VERSION.SDK_INT < 28) {
return;
}
exemptAll();
}
}
参考的github地址:github.com/tiann/FreeR…