Java类加载器-动态加载外部dex
Android 类加载
Android 只能加载识别 dex 文件,因此需要将 .java
文件编译 .class
文件,然后将 .class
优化为 .dex
文件。
过程:.java -> .class -> .dex
下面来练习如何去加载一个 dex 文件,并调用 dex 中的方法。
获取需要动态加载的 dex 文件
- 编写 DynamicClass.java 类
public class DynamicClass {
public static void main(String[] args){
print();
}
public static void print() {
System.out.println("Hello Dynamic");
}
}
- 编译 DynamicClass.java
编译后会得到 DynamicClass.class,注意:我这里将环境变量 JAVA_HOME 指定为 JDK1.6,不然用 dx 转化编译出来的 class 可能有一些奇怪的问题。
javac DynamicClass.java
- 优化 class 文件得到 dex 文件
Android SDK 提供了 dx 工具,可以将 class 转化为 dex 文件。
dx 工具位于:build-tools/23.0.2/dx 23.0.2是版本号,build-tools 下有很多版本,随便选一个即可。
将 DynamicClass.class 转化为 dex 文件 dynamic.dex
dx --dex --output=dynamic.dex DynamicClass.class
- 将
dynamic.dex
上传到/sdcard
根目录下
adb push dynamic.dex /sdcard
加载并调用.dex里面的方法
在 Android
中加载 dex
文件是通过以下两种类加载器 DexClassLoader
或者 PathClassLoader
来加载的。
DexClassLoader
可以加载含有
dex
文件的jar
或者apk
文件,也可以从SD
卡 中加载未安装的 apk;
- PathClassLoader
加载已经安装的apk文件。
DexClassLoader
因为我们是需要外部动态加载 dex
文件,因此只能使用 DexClassLoader
来加载 dex 文件了。
- 指定存放 dex 文件的路径
在上面的步骤中,我们已经将生成的
dex
文件拷贝到sdcard
目录下了。
String dexPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dynamic.dex";
构造一个 DexClassLoader
DexClassLoader dexClassLoader = new DexClassLoader(dexPath,
Environment.getExternalStorageDirectory().toString(), null, loader);
- 加载 dex 文件中的类 DynamicClass
Class dynamicClass = dexClassLoader.loadClass("DynamicClass");
- 反射调用 DynamicClass 的 print() 方法
Method printMethod = dynamicClass.getMethod("print");
printMethod.invoke(dynamicClass.newInstance());
DynamicClass 类完整的代码如下:
public class DexLoader {
public static void dynamicLoad(ClassLoader loader) {
//动态加载 dex
String dexPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dynamic.dex";
System.out.println(dexPath);
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, Environment.getExternalStorageDirectory().toString(), null, loader);
try {
Class dynamicClass = dexClassLoader.loadClass("DynamicClass");
Method printMethod = dynamicClass.getMethod("print");
printMethod.invoke(dynamicClass.newInstance());
System.out.println("动态加载成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("动态加载失败:" + e.toString());
}
}
}
记录于 2019年4月10号晚