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) {
    }
}

最後推薦使用最後一種,成本最低效果最好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章