Android之ClassLoader和插件
Android中的ClassLoader本质上跟JRE中的一样,但Android的字节码格式不一样,Android下的ClassLoader不能直接加载普通的jar包,需要使用dex2jar工具中的d2j-jar2dex.bat, 把jar转换为classes.dex,然后把classes.dex放到jar文件中作为ClassLoader的源数据;
1)我们先生成一个Android需要的JAR;
源码:
package test;
public class AnPluginDemo {
public int getValue() {
return 100;
}
}
2)打包成jar;
3)使用dex2jar工具中的d2j-jar2dex.bat, 把jar转换为classes.dex;
4)把classes.dex放到一个新的jar中, AnPluginDemo.jar;
5)建立一个Android工程;
6)把AnPluginDemo.jar放到assets下;
7)加载插件并运行
void loadAndInvoke(String name) {
try {
File dir = getDir("plugin", Context.MODE_PRIVATE);
byte[] bs = readDataFromAsserts("plugin/" + name);// 读取插件数据
String path = new File(dir, name).getAbsolutePath();// 插件保存的位置
Files.writeFile(path, bs);// 保存插件
// 创建类加载器,把dex加载到虚拟机中
DexClassLoader loader = new DexClassLoader(//
path,//插件路径,可以用冒号分隔多个, 可以是jar(内有classes.dex)或apk格式
dir.getAbsolutePath(),//优化后保存的目录
null,//so文件位置
this.getClass().getClassLoader()//父ClassLoader
);
Class<?> c = loader.loadClass("test/AnPluginDemo");// 加载需要使用的类
Method m = c.getMethod("getValue");// 取得方法
Object o = c.newInstance();// 创建对象
Object r = m.invoke(o);// 调用方法
showTipDialog("R:" + r);//显示执行结果
} catch (Exception e) {
e.printStackTrace();
showTipDialog("R:" + e.getClass());
}
}