安卓插件化学习 - 类的加载
引言
本次博客主要学习插件化知识,插件化多用于热修复,app主从功能分离等。通过学习ClassLoader的基本知识掌握类的加载。
一、类的加载
1. 原理
类加载器之间的继承关系如上图所示,一般宿主apk通过PathClassLoader进行加载,插件apk通过DexClassLoader进行加载。宿主apk启动时,类加载顺序图如下。
从宿主的类加载顺序看,最终调用到了宿主dexElements,那么我们实现插件化的方法是用DexClassLoader加载插件apk后,利用反射获取插件的dexElements,然后拷贝到宿主的dexElements。这样宿主apk就有了插件apk的dexElements信息,也就是能在宿主apk内利用反射调用到插件的类、方法等。方案如下。
这里注意下:
1)实例化DexClassLoader加载插件
跟宿主类加载
没有先后顺序之分,两者的目的在于改变dexElements的信息。
2)而在宿主调用插件化的类、方法之前,就必须要把插件的dexElements合并到宿主的dexElements里。
3)源码中,类PathClassLoader和类DexClassLoader中的方法和变量都能在其父类BaseDexClassLoader中找到,子类的构造函数提供参数输入。
2. 代码
2.1 宿主apk代码
2.1.1 插件管理器
创建一个空白activity的工程,用一个单例加载插件apk,此段代码为核心代码。
public class PluginManager {
private static final String TAG = "PluginManager";
private static PluginManager instance;
private Context context;
private PluginManager(Context context) {
this.context = context;
}
public static PluginManager getInstance(Context context) {
if (instance == null) {
instance = new PluginManager(context);
}
return instance;
}
public void init() {
try {
loadApk();
} catch (Exception e) {
e.printStackTrace();
}
}
private void loadApk() throws Exception {
//加载插件的apk路径
String pluginApkPath = context.getExternalFilesDir(