美文网首页
绕过Android P以上非公开API限制的办法

绕过Android P以上非公开API限制的办法

作者: Jk_zhuang | 来源:发表于2021-01-16 12:46 被阅读0次

    Android P上引入了针对非公开API的限制,对开发者来说,特别是对于需要维护具有众多“黑科技”的项目的开发者来说,这绝对是一个灾难。

    目前Google商店对于应用Target SDK版本的要求是29,假设你的应用如果需要在Google商店上架,意味着你不得不去适配非公开API的限制。

    要把项目里面所有的非公开API都替换为其它的实现?看起来是最终最好的方案,但是实现起来困难诸多,工作量也非常大。

    我们可以通过使用元反射的形式,即借助系统的类,来反射我们需要的东西,直接上代码:

    /**
     * reflection util
     */
    public class ReflectionUtil {
    
        public static final String TAG = "ReflectionUtil";
    
        private static Method sForNameMethod;
        private static Method sGetDeclaredMethod;
        private static Method sGetFieldMethod;
    
        /**
         * init reflection and cache it
         */
        static {
            try {
                sForNameMethod = Class.class.getDeclaredMethod("forName", String.class);
                sGetDeclaredMethod = Class.class
                        .getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
                sGetFieldMethod = Class.class.getDeclaredMethod("getDeclaredField", String.class);
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    
        /**
         * get filed
         *
         * @param src the instance
         * @param clzName the class name
         * @param filedName the filed name
         * @param defObj the default val
         * @return the filed of the instance
         */
        @NonNull
        public static Object getFiledObj(@NonNull Object src, @NonNull String clzName,
                @NonNull String filedName, @NonNull Object defObj) {
            Object result = defObj;
            try {
                Field field = getFiled(clzName, filedName);
                if (field != null) {
                    result = field.get(src);
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
    
            return result;
        }
    
        /**
         * get filed
         *
         * @param clzName the class name
         * @param filedName the filed name
         * @return the class filed
         */
        @Nullable
        public static Field getFiled(@NonNull String clzName, @NonNull String filedName) {
            Field field = null;
            if (canReflection()) {
                try {
                    Class<?> clz = (Class<?>) sForNameMethod.invoke(null, clzName);
                    field = (Field) sGetFieldMethod.invoke(clz, filedName);
                    field.setAccessible(true);
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
    
            return field;
        }
    
        /**
         * set filed to the instance
         *
         * @param src the instance
         * @param clzName the class name
         * @param filedName the filed name
         * @param tarObj target object
         */
        public static void setFiled(@NonNull Object src, @NonNull String clzName,
                @NonNull String filedName, Object tarObj) {
            try {
                Field field = getFiled(clzName, filedName);
                if (field != null) {
                    field.set(src, tarObj);
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    
        /**
         * get method
         *
         * @param clzName the class name
         * @param methodName the method name
         * @param clzArgs method params
         * @return method
         */
        @Nullable
        public static Method getMethod(@NonNull String clzName, @NonNull String methodName,
                Class[] clzArgs) {
            Method method = null;
            if (canReflection()) {
                try {
                    Class<?> clz = (Class<?>) sForNameMethod.invoke(null, clzName);
                    method = (Method) sGetDeclaredMethod.invoke(clz, methodName, clzArgs);
                    method.setAccessible(true);
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
            return method;
        }
    
        /**
         * invoke method
         *
         * @param src the instance
         * @param clzName the class name
         * @param methodName the method name
         * @param clzArgs args class array
         * @param objArgs args
         * @return obj
         */
        public static Object invokeMethod(@NonNull Object src, @NonNull String clzName,
                @NonNull String methodName, Class[] clzArgs, Object... objArgs) {
            Object result = null;
            try {
                Method method = getMethod(clzName, methodName, clzArgs);
                if (method != null) {
                    result = method.invoke(src, objArgs);
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
            return result;
        }
    
        /**
         * check can reflation
         *
         * @return can use reflection or no
         */
        private static boolean canReflection() {
            boolean canReflection = true;
            if (sForNameMethod == null || sGetDeclaredMethod == null || sGetFieldMethod == null) {
                canReflection = false;
            }
            return canReflection;
        }
    }
    

    使用的方法也不难,例如我们需要反射下面的方法:

    package android.telephony;
    
    public class TelephonyManager {
    
        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
        public int getDataNetworkType(int subId) {
            
        }
    }
    

    调用代码如下:

        Object obj = ReflectionUtil.invokeMethod(tm, "android.telephony.TelephonyManager", 
            "getDataNetworkType", new Class[]{int.class}, defaultDataSubId);
        int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
        if (obj instanceof Integer) {
            networkType = (Integer) obj;
        }
    

    转载请注明出处:https://www.jianshu.com/p/058fe5a62607
    元反射方式来自于文章:另一种绕过 Android P以上非公开API限制的办法

    相关文章

      网友评论

          本文标题:绕过Android P以上非公开API限制的办法

          本文链接:https://www.haomeiwen.com/subject/cwrnaktx.html