Android 豁免所有hide灰名单调用警告,做到不弹窗,logcat不提示,隐藏代码能并反射

从 android 9.0 开始,当代码调用某些系统api的时候,会因为api的一些判定灰名单级别,不同程度的对app做出提醒,最严重的是直接弹窗提醒,次之是会在logcat打印出调用内容。

具体api名单列表:https://developer.android.google.cn/about/versions/10/non-sdk-q

但有些情况下我们确实要使用这些api,下面是我总结了以下几种方案:

1. 反射禁止弹窗

优点:

  • 能避免弹窗

缺点:

  • 不能避免代码扫描,logcat打印
  • 某些类方法用 getMethod 无法发现,无法获取到,因此也就无法反射
try {
    Class aClass = Class.forName("android.content.pm.PackageParser$Package");
    Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class);
    declaredConstructor.setAccessible(true);
} catch (Exception e) {
    e.printStackTrace();
}
try {
    Class cls = Class.forName("android.app.ActivityThread");
    Method declaredMethod = cls.getDeclaredMethod("currentActivityThread");
    declaredMethod.setAccessible(true);
    Object activityThread = declaredMethod.invoke(null);
    Field mHiddenApiWarningShown = cls.getDeclaredField("mHiddenApiWarningShown");
    mHiddenApiWarningShown.setAccessible(true);
    mHiddenApiWarningShown.setBoolean(activityThread, true);
} catch (Exception e) {
    e.printStackTrace();
}

2. 使用元反射(能避免弹窗,logcat打印,只用使用元反射的才能达到效果)

优点:

  • 能避免弹窗
  • 能避免代码扫描,logcat打印
  • 某些用getMethod无法发现的方法,可以被发现了了,也可以反射了

缺点:

  • 对于正常反射的代码,无效,会弹窗,打印logcat
try {
    forName = Class.class.getDeclaredMethod("forName", String.class);
    // invoke = Method.class.getMethod("invoke", Object.class, Object[].class);
    // 反射获取方法
    getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
    getMethod = Class.class.getDeclaredMethod("getMethod", String.class, Class[].class);

    // 反射获取变量
    getDeclaredField = Class.class.getDeclaredMethod("getDeclaredField", String.class);
    getField = Class.class.getDeclaredMethod("getField", String.class);

    // 反射实例化代码
    getDeclaredConstructor = Class.class.getDeclaredMethod("getDeclaredConstructor", Class[].class);
    getConstructor = Class.class.getDeclaredMethod("getConstructor", Class[].class);
    newInstance = Constructor.class.getDeclaredMethod("newInstance", Object[].class);
} catch (Throwable igone) {
}

反射时,原来的反射代码应这样写:

正常的反射

Method getStringMethod = A.class.getDeclaredConstructor("getString");
getStringMethod.invoke(new A());

元反射

Method getStringMethod = getDeclaredConstructor.invoke(A.class,"getString");
getStringMethod.invoke(new A());

3. 元反射基础上,本进程将所有灰黑api加入白名单(能避免弹窗,logcat打印,后续即使不使用元反射也能达到效果)

优点:

  • 能避免弹窗
  • 能避免代码扫描,logcat打印
  • 某些用getMethod无法发现的方法,可以被发现了了,也可以反射了
  • 对于正常反射的代码,仍然不会弹窗,打印logcat
try {
    forName = Class.class.getDeclaredMethod("forName", String.class);
    // invoke = Method.class.getMethod("invoke", Object.class, Object[].class);
    // 反射获取方法
    getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
    getMethod = Class.class.getDeclaredMethod("getMethod", String.class, Class[].class);

    // 反射获取变量
    getDeclaredField = Class.class.getDeclaredMethod("getDeclaredField", String.class);
    getField = Class.class.getDeclaredMethod("getField", String.class);

    // 反射实例化代码
    getDeclaredConstructor = Class.class.getDeclaredMethod("getDeclaredConstructor", Class[].class);
    getConstructor = Class.class.getDeclaredMethod("getConstructor", Class[].class);
    newInstance = Constructor.class.getDeclaredMethod("newInstance", Object[].class);
} catch (Throwable igone) {
}
if (Build.VERSION.SDK_INT > 27) {
    /*
    * 设置豁免所有hide api
    * http://androidxref.com/9.0.0_r3/xref/art/test/674-hiddenapi/src-art/Main.java#100
    * VMRuntime.getRuntime().setHiddenApiExemptions(new String[]{"L"});
    */
    try {
        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 igone) {
    }
}

最后推荐使用最后一种,成本最低效果最好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

痕迹丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值