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文件.
在通过反射利用类名得到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;
}
}



