绕过Android P以上非公开Api反射的限制

2,088 阅读1分钟

 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…