插件包类加载器是通过创建 DexClassLoader 获得的 , 需要传入插件包中的 dex 字节码类 ;
/** * 插件化框架核心类 */ public class PluginManager { /** * 类加载器 * 用于加载插件包 apk 中的 classes.dex 文件中的字节码对象 */ private DexClassLoader mDexClassLoader; /** * 加载插件 * @param context 加载插件的应用的上下文 * @param loadPath 加载的插件包地址 */ public void loadPlugin(Context context, String loadPath) { this.mContext = context; // DexClassLoader 的 optimizedDirectory 操作目录必须是私有的 // ( 模式必须是 Context.MODE_PRIVATE ) File optimizedDirectory = context.getDir("plugin", Context.MODE_PRIVATE); // 创建 DexClassLoader mDexClassLoader = new DexClassLoader( loadPath, // 加载路径 optimizedDirectory.getAbsolutePath(), // apk 解压缓存目录 null, context.getClassLoader() // DexClassLoader 加载器的父类加载器 ); } /** * 获取类加载器 * @return */ public DexClassLoader getmDexClassLoader() { return mDexClassLoader; } }
二、" 宿主 " 模块加载 " 插件 " 模块中的资源文件
在 " 宿主 " 模块中 , 使用 Resources 是无法获取到 " 插件 " 模块中的资源文件的 , 在使用 " 插件 " 模块中的资源文件之前 , 必须先加载其中的资源文件 ;
/** * 该 Activity 只是个空壳 ; * 主要用于持有从 apk 加载的 Activity 类 * 并在 ProxyActivity 声明周期方法中调用对应 PluginActivity 类的生命周期方法 */ public class ProxyActivity extends AppCompatActivity { /** * 需要使用插件包中加载的资源 * @return */ @Override public Resources getResources() { return PluginManager.getInstance().getmResources(); } }
插件包中的 Resources 加载过程如下 :
首先 , 通过反射创建 AssetManager ,
然后 , 通过反射获取 AssetManager 中的 addAssetPath 隐藏方法 ,
再后 , 调用 AssetManager 的 addAssetPath 方法 ,
最后 , 通过 AssetManager 创建 Resources 对象 ;
/** * 插件化框架核心类 */ public class PluginManager { /** * 加载插件 * @param context 加载插件的应用的上下文 * @param loadPath 加载的插件包地址 */ public void loadPlugin(Context context, String loadPath) { this.mContext = context; // 加载资源 try { // 通过反射创建 AssetManager AssetManager assetManager = AssetManager.class.newInstance(); // 通过反射获取 AssetManager 中的 addAssetPath 隐藏方法 Method addAssetPathMethod = assetManager. getClass(). getDeclaredMethod("addAssetPath"); // 调用反射方法 addAssetPathMethod.invoke(assetManager, loadPath); // 获取资源 mResources = new Resources( assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration() ); } catch (IllegalAccessException e) { // 调用 AssetManager.class.newInstance() 反射构造方法异常 e.printStackTrace(); } catch (InstantiationException e) { // 调用 AssetManager.class.newInstance() 反射构造方法异常 e.printStackTrace(); } catch (NoSuchMethodException e) { // getDeclaredMethod 反射方法异常 e.printStackTrace(); } catch (InvocationTargetException e) { // invoke 执行反射方法异常 e.printStackTrace(); } } /** * 获取插件包中的资源 * @return */ public Resources getmResources() { return mResources; } }