栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android 获取APK中的所有类 或 指定接口的所有实现类

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 获取APK中的所有类 或 指定接口的所有实现类

问题分解 1. 获取所有的类

Android App所有Java类都是封装到Dex文件中, 让虚拟机执行, 所以我们可以通过DexFile.entries();来获取指定DexFile中所封装的所有完整类名, 然后通过反射就可以获取类了.

如何获取DexFile A. 直接创建DexFile对象
 DexFile df = new DexFile(context.getPackageCodePath(););

但这种方法不适用于多个dex的情况, 而且其构造方法将在API26被弃用

B. 通过类加载器获取DexFile

查看baseDexClassLoader的源码 可知, 其私有对象pathList是DexFile的容器, 所以我们可以通过反射来获取这个容器中所有的DexFile.
同时, 也可以找到多个Dex文件.

2. 筛选出实现指定接口的类

在通过反射利用类名得到Class对象A后, 我们需要判断其是否实现了指定接口B,通过B.isAssignableFrom(A)可以分辨, 当其返回true,则说明B是A的实现类或子接口.

工具类
public class ClassUtils {

    private static baseDexClassLoader mClassLoader = (baseDexClassLoader) Thread.currentThread().getContextClassLoader();

    
    public static void setClassLoader(Context context) {
        if (mClassLoader == null) {
            mClassLoader = (baseDexClassLoader) context.getClassLoader();
        }
    }

    
    public static  List> getAllClassByInterface(Class interfaceClass) {
        Package pkg = interfaceClass.getPackage();
        String pkgName = pkg != null ? pkg.getName() : "";
        return getAllClassByInterface(interfaceClass, pkgName);
    }

    

    public static  List> getAllClassByInterface(Class interfaceClass, String packageName) {
        if (!interfaceClass.isInterface()) {
            throw new IllegalArgumentException("interfaceClass must be a Interface!");
        }
        List> returnClassList = new ArrayList<>();
        List> allClass = getClasses(packageName);
        //排除本身
        allClass.remove(interfaceClass);

        for (Class c : allClass) {
            if (interfaceClass.isAssignableFrom(c)) {
                returnClassList.add((Class) c);
            }
        }
        return returnClassList;
    }

    
    private static List> getClasses(String packageName) {
        ArrayList> classes = new ArrayList<>();
        for (String str : getAllClassesName(packageName)) {
            try {
                classes.add(getClassByName(str));
            } catch (Throwable ignored) {
            }
        }
        return classes;
    }

    
    private static Set getAllClassesName(String packageName) {
        Set classes = new linkedHashSet<>();
        for (DexFile df : getMultiDex()) {
            //获取df中的元素  这里包含了所有可执行的类名 该类名包含了包名+类名的方式
            Enumeration enumeration = df.entries();
            while (enumeration.hasMoreElements()) {
                String className = enumeration.nextElement();
                if (packageName.isEmpty() || className.startsWith(packageName)) {
                    classes.add(className);
                }
            }
        }
        return classes;
    }

    
    private static List getMultiDex() {
        ArrayList res = new ArrayList<>();
        try {
            Field f = getField("pathList", dalvik.system.baseDexClassLoader.class);
            Object pathList = getObjectFromField(f, mClassLoader);
            Field f2 = getField("dexElements", getClassByName("dalvik.system.DexPathList"));
            Object[] list = (Object[]) getObjectFromField(f2, pathList);
            Field f3 = getField("dexFile", getClassByName("dalvik.system.DexPathList$Element"));


            if (list != null) {
                for (Object o : list) {
                    DexFile d = (DexFile) getObjectFromField(f3, o);
                    res.add(d);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return res;
    }

    private static Field getField(String field, Class className) {
        try {
            return className.getDeclaredField(field);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Class getClassByName(String className) throws ClassNotFoundException {
        return mClassLoader.loadClass(className);
    }

    private static Object getObjectFromField(Field field, Object arg) {
        try {
            field.setAccessible(true);
            return field.get(arg);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/322743.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号