最近琢磨了 Android 插件化方面的实现,子曾曰过:好记性不如烂笔头,于是对自己近日所得做个总结。
基本概念
-
Android 插件化一般指已安装的 App 直接调用未安装的 App 或运行其类方法。 Android 插件化有以下几点好处:
-
(1)模块解耦
(2)突破 .dex 文件方法数限制
(3)动态更新
对于第2点其实使用 Google 提供的 multidex support library 可轻松实现多 dex 文件拆分,关于 dex 方法数的限制可参考 Google 官方文档 Building Apps with Over 65K Methods。
类的加载
插件化中除了一般类的加载还包括 Activity, Service 等组件的加载和运行,这里只讨论单纯的类加载,有兴趣的朋友可研究下文提到的几个开源库。
类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例。Android 的 DVM(Dalvik Virtual Machine) 中 .class 文件还会进一步转换成 .dex 文件供 DVM 的 PathClassLoader 加载器加载。
Android 中类的加载器主要有:
DexClassLoader
可以加载包含 dex 的 jar 和 apk 文件。加载的文件可放置于sdcard目录下,但不要这么做,无权限控制的 sdcard 分区的 dex 文件易被破坏或代码注入攻击。
PathClassLoader。
Android 本身使用的系统加载器,用于加载 App 本身,只能加载已经安装到Android系统中的apk文件。
从上面可以看出,插件化的动态加载是使用 DexClassLoader 实现。下面简单的介绍如何实现类的动态加载。
动态加载实现
-
插件类是动态加载的,那么本地(主 App)便没有插件类的定义,要获取和运行插件类和方法有以下方法:
-
(1)反射
(2)继承接口或虚类
使用反射可获取插件类的全部方法和成员变量,但使用反射比较复杂而且需要硬编码方法名变量名等,使用继承公共接口的方式更加方便安全。
代码实现
下面的示例可在我的 github 中获取 BlogDemo库,参考示例工程dynamic-load-demo
。
这里先定义一个插件类的接口:
// ModuleInterface.java
public interface ModuleInterface {
String print(String msg);
}
定义插件类实现 ModuleInterface