Android 开发中,Java 程序通常由 JVM 虚拟机通过类加载器(ClassLoader)加载 .jar 文件中的类。而在 Android 平台上,使用的是 Dalvik 或 ART 虚拟机,无法直接加载标准的 .jar 文件,必须将其优化为 .dex 格式才能运行。
1. 将 .jar 文件优化成 .dex 文件
在 Android SDK 环境中,首先需要将 Java 源代码编译为 .class 文件,然后打包成 .jar 文件。这一步与普通 Java 程序的编译过程一致。随后,利用 Android SDK 提供的 DX 工具将 .jar 文件转换为 .dex 文件。DX 工具通常位于 android-sdk/build-tools/<具体版本>/目录下。
转换命令如下:
dx --dex --output=target.dex origin.jar
其中 target.dex 是生成的目标文件,origin.jar 是源文件。
此外,还有一种常见方式是将代码编译成 APK 文件,然后解压出其中的 .dex 文件直接使用。由于 APK 本质上是 ZIP 格式的压缩包,内部包含经过优化的 .dex 文件,因此 Android 的类加载器在加载 APK 时会自动解压内部的 .dex 内容。这意味着加载 .jar、.apk 或直接加载 .dex 文件在底层机制上是等价的。
2. 加载并调用 .dex 里面的方法
Android 虚拟机不能像 JVM 那样直接使用 ClassLoader 加载任意路径的 .dex 文件,而是需要使用 DexClassLoader 或 PathClassLoader。这两个类都是 ClassLoader 的子类,主要区别在于:
- DexClassLoader:可以加载 .jar、.apk、.dex 文件,支持从 SD 卡等外部存储加载未安装的 APK。
- PathClassLoader:只能加载系统中已安装的 APK 文件路径,通常用于系统应用或已安装应用的类加载。
2.1 DexClassLoader 构造参数详解
使用 DexClassLoader 前,需要理解其构造方法的四个参数:
public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)
- dexPath:待加载的 .dex、.jar 或 .apk 文件的绝对路径。
- optimizedDirectory:优化后的 .dex 文件存放目录。Android 虚拟机需要将加载的字节码进行优化(如生成 OAT 文件),该目录必须是当前应用可写的内部存储路径,不能直接加载外部存储的原始文件。
- libraryPath:本地库(.so 文件)的搜索路径,通常设为 null。
- parent:父类加载器,通常传入当前应用的 getClassLoader(),遵循双亲委派模型。
示例代码如下:
// 外部路径,例如 SD 卡或下载目录
File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "test_dexloader.jar");
// 内部缓存目录,用于存放优化后的 dex 文件
File dexOutputDir = this.getDir(, Context.MODE_PRIVATE);
(
optimizedDexOutputPath.getAbsolutePath(),
dexOutputDir.getAbsolutePath(),
,
getClassLoader()
);


