1 背景
以下内容摘录自官方文档
针对非 SDK 接口的限制
从 Android 9(API 级别 28)开始,Android 平台对应用能使用的非 SDK 接口实施了限制。只要应用引用非 SDK 接口或尝试使用反射或 JNI 来获取其句柄,这些限制就适用。这些限制旨在帮助提升用户体验和开发者体验,为用户降低应用发生崩溃的风险,同时为开发者降低紧急发布的风险。如需详细了解有关此限制的决定
方法反射(Method Reflection)
Java 类java.lang.reflect.Method
实例是对类方法(Method)的反射。Method
类继承自通用抽象父类Executable
,其自身是不可变(Immutable)类。
方法 | 描述 |
---|---|
Method[] getMethods() | 返回目标类中所有可访问的公开方法,包括从父类继承的公开方法。 |
Method[] getDeclaredMethods() | 返回目标类中所有方法,不包括从父类继承的方法。 |
Method getMethod(String name, Class... parameterTypes) | 根据方法名与参数类型取得目标方法对象。 |
Method getDeclaredMethod(String name, Class... parameterTypes) | 根据方法名与参数类型取得目标方法对象,不包括从父类继承的方法。 |
大白话解读:
-
getDeclaredMethod:获取当前类的所有声明的方法,包括public、protected和private修饰的方法。需要注意的是,这些方法一定是在当前类中声明的,从父类中继承的不算,实现接口的方法由于有声明所以包括在内。
-
getMethod:获取当前类和父类的所有public的方法。这里的父类,指的是继承层次中的所有父类。比如说,A继承B,B继承C,那么B和C都属于A的父类。
案例:
整理了一份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
typescript
代码解读
复制代码
public class Fruit { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
scala
代码解读
复制代码
public class Apple extends Fruit { private int price; public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } }
java
代码解读
复制代码
import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ReflectTest { public static void main(String[] args) throws Exception { //正常调用 Apple apple = new Apple(); apple.setPrice(5); System.out.println("Apple Price:" + apple.getPrice()); //使用反射调用-getMethod Class clz = Class.forName("Apple"); Method setPriceMethod = clz.getMethod("setPrice", int.class); Constructor appleConstructor = clz.getConstructor(); Object appleObj = appleConstructor.newInstance(); setPriceMethod.invoke(appleObj, 14); Method getPriceMethod = clz.getMethod("getPrice"); System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj)); System.out.println("================================"); //静态方法反射调用 Method showMethod = clz.getMethod("show",int.class); showMethod.invoke(null,9); System.out.println("================================"); //获取本类+父类所有方法 Method[] methods = clz.getMethods(); for (Method method : methods) { System.out.println("method:" + method); } System.out.println("================================"); //获取本类所有方法 Method[] declaredMethods = clz.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println("declaredMethod:" + method); } System.out.println("================================"); //使用反射调用-getDeclaredMethod setPriceMethod = clz.getDeclaredMethod("setPrice", int.class); appleConstructor = clz.getConstructor(); appleObj = appleConstructor.newInstance(); setPriceMethod.invoke(appleObj, 22); getPriceMethod = clz.getDeclaredMethod("getPrice"); System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj)); } }
运行结果:
vbnet
代码解读
复制代码
Apple Price:5 Apple Price:14 ================================ show static method called,price:9 ================================ method:public static void Apple.show(int) method:public void Apple.setPrice(int) method:public int Apple.getPrice() method:public java.lang.String Fruit.getName() method:public void Fruit.setName(java.lang.String) method:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException method:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException method:public final void java.lang.Object.wait() throws java.lang.InterruptedException method:public boolean java.lang.Object.equals(java.lang.Object) method:public java.lang.String java.lang.Object.toString() method:public native int java.lang.Object.hashCode() method:public final native java.lang.Class java.lang.Object.getClass() method:public final native void java.lang.Object.notify() method:public final native void java.lang.Object.notifyAll() ================================ declaredMethod:public static void Apple.show(int) declaredMethod:public void Apple.setPrice(int) declaredMethod:public int Apple.getPrice() ================================ Apple Price:22
4 源码分析
以访问Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V为例
kotlin
代码解读
复制代码
try { val runtimeClass = Class.forName("dalvik.system.VMRuntime") val nativeLoadMethod = runtimeClass.getDeclaredMethod( "setTargetSdkVersionNative", *arrayOf<Class<*>?>(Int::class.javaPrimitiveType) ) Log.i(TAG, "setTargetSdkVersionNative success,nativeLoadMethod:$nativeLoadMethod") } catch (e: Throwable) { e.printStackTrace() }
然后运行时抛出了异常NoSuchMethodException
php
代码解读
复制代码
2024-06-20 07:57:04.716 29837-29837 .ndk.hidden.api com.ygq.ndk.hidden.api W Accessing hidden method Ldalvik/system/VMRuntime;->setTargetSdkVersionNative(I)V (blocked, reflection, denied) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W java.lang.NoSuchMethodException: dalvik.system.VMRuntime.setTargetSdkVersionNative [int] 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at java.lang.Class.getMethod(Class.java:2937) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at java.lang.Class.getDeclaredMethod(Class.java:2914) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at com.ygq.ndk.hiddenapi.MainActivity.onCreate$lambda$0(MainActivity.kt:32) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at com.ygq.ndk.hiddenapi.MainActivity.$r8$lambda$bSb4PNoYIVmHUKhD73qlXfirQvk(Unknown Source:0) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at com.ygq.ndk.hiddenapi.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:0) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at android.view.View.performClick(View.java:7799) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at android.view.View.performClickInternal(View.java:7776) 2024-06-20 07:57:04.717 29837-29837 System.err com.ygq.ndk.hidden.api W at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at android.view.View$PerformClick.run(View.java:31213) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at android.os.Handler.handleCallback(Handler.java:958) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at android.os.Handler.dispatchMessage(Handler.java:99) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at android.os.Looper.loopOnce(Looper.java:224) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at android.os.Looper.loop(Looper.java:318) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at android.app.ActivityThread.main(ActivityThread.java:8754) 2024-06-20 07:57:04.718 29837-29837 System.err com.ygq.ndk.hidden.api W at java.lang.reflect.Method.invoke(Native Method) 2024-06-20 07:57:04.718 29837-298