用到生成dex命令
dx --dex --output = xx.dex com\xxxx\xxx\xxx.class
public class HotFixUtil {
private final static String PATH_LIST_FIELD = "pathList";//pathList 属性
private final static String DEX_ELEMENTS_FIELD = "dexElements";//dexElements 属性
/**
* makeDexElements(List<File> files, File optimizedDirectory,
* List<IOException> suppressedExceptions, ClassLoader loader)
*/
private final static String MAKE_DEX_ELEMENTS = "makeDexElements";//将dex 变成 elements 数组
public static void install(Application application, File dexFile) throws IllegalAccessException, InvocationTargetException {
//1.获取 当前项目类加载器
ClassLoader classLoader = application.getClassLoader();
//2.获取类加载器中的 pathList
Field pathListField = findField(classLoader, PATH_LIST_FIELD);
Object pathList = pathListField.get(classLoader);
//3.获取旧的 dexElements 数组
Field fieldElement = findField(pathList, DEX_ELEMENTS_FIELD);
Object[] oldElements = (Object[]) fieldElement.get(pathList);
//4.根据新的dex 文件获取需要插入的dexElements 数组
//第一个参数
List<File> dexFiles = new ArrayList<>();
dexFiles.add(dexFile);
//第二个参数
File optimizedDirectory = application.getCacheDir();
//第三个参数
List<IOException> suppressedExceptions = new ArrayList();
Method method = findMethod(pathList, MAKE_DEX_ELEMENTS, List.class, File.class, List.class, ClassLoader.class);
Object[] dexElements = (Object[]) method.invoke(pathList, dexFiles, optimizedDirectory, suppressedExceptions, classLoader);
//5.将两个dexElements 合并成一个新的
Class<?> componentType = dexElements.getClass().getComponentType();
Object[] newElements = (Object[]) Array.newInstance(componentType, oldElements.length + dexElements.length);
System.arraycopy(dexElements, 0, newElements, 0, dexElements.length);
System.arraycopy(oldElements, 0, newElements, dexElements.length, oldElements.length);
//6.将新的dexElements 数组设置给 pathList
fieldElement.set(pathList, newElements);
}
/**
* 根据name 查询对象中属性
* 如果当前类没有 就去父类找
*
* @param instance
* @param fieldName
* @return
*/
private static Field findField(Object instance, String fieldName) {
Class<?> aClass = instance.getClass();
while (aClass != null) {
try {
Field field = aClass.getDeclaredField(fieldName);
if (!field.isAccessible()) {
field.setAccessible(true);
}
return field;
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
aClass = aClass.getSuperclass();
}
return null;
}
/**
* 查找对象中对应方法
*
* @param instance
* @param methodName
* @return
*/
private static Method findMethod(Object instance, String methodName, Class<?>... args) {
Class<?> aClass = instance.getClass();
while (aClass != null) {
try {
Method method = aClass.getDeclaredMethod(methodName, args);
if (!method.isAccessible()) {
method.setAccessible(true);
}
return method;
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
aClass = aClass.getSuperclass();
}
return null;
}
}