用到生成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 數(shù)組
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 數(shù)組
Field fieldElement = findField(pathList, DEX_ELEMENTS_FIELD);
Object[] oldElements = (Object[]) fieldElement.get(pathList);
//4.根據(jù)新的dex 文件獲取需要插入的dexElements 數(shù)組
//第一個參數(shù)
List<File> dexFiles = new ArrayList<>();
dexFiles.add(dexFile);
//第二個參數(shù)
File optimizedDirectory = application.getCacheDir();
//第三個參數(shù)
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 數(shù)組設(shè)置給 pathList
fieldElement.set(pathList, newElements);
}
/**
* 根據(jù)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;
}
/**
* 查找對象中對應(yīng)方法
*
* @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;
}
}