最近尝试热修复,反射调用补丁类,发现android O的类提前加载了,但没有初始化,所以出现了补丁无法生效的问题,对比一下之前版本,发现Android 6.0 执行到指定位置才去加载,并且初始化,因此想法去证实这个问题。
一、为什么要注入ClassLoader?
- 观察Android中类的加载时机、类的机制、定为加载问题
- 观察补丁包或者插件加载机制
二、替换方式
默认形式
PathClassloader.parent <- PathClassloader
方案一:
PathClassloader.parent <- Hook ClassLoader <- PathClassloader
这种方案实现比较简单
public class DelegateClassLoader extends PathClassLoader {
private ClassLoader mPathClassLoader;
private DelegateClassLoader(String dexPath,ClassLoader parentClassLoader) {
super(dexPath, parentClassLoader);
mPathClassLoader = getClass().getClassLoader();
}
//PathClassloader.parent <- PathClassloader ====> PathClassloader.parent <- Hook ClassLoader <- PathClassloader
public static synchronized void hook(ClassLoader pathClassLoader) throws NoSuchFieldException, IllegalAccessException {
ClassLoader classLoader = new DelegateClassLoader("",pathClassLoader.getParent());
Field parentField = ClassLoader.class.getDeclaredField("parent");
parentField.setAccessible(true);
parentField.set(pathClassLoader,classLoader);
Thread.currentThread().setContextClassLoader(classLoader);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
return super.loadClass(name, resolve);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return super.findClass(name);
}
}
调用方式如下
public class BaseHotfixApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
try {
DelegateClassLoader.hook(base.getClassLoader());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {