生成dex文件
step1:将java文件编译成class文件
命令行方式:
javac YourJavaFile.java
编译后文件夹查找
android下build后,YouProject\Module\build\intermediates\javac\debug\classes
step2: 将class 文件打包成jar
说明, “./” 是当前目录 ,直接 “.” 也可以
D:\input>jar cvf 1.jar ./
step3:将jar文件 转 dex文件
D:\Android_Sdk\build-tools\34.0.0>d8 --release --output classes.zip d:/input/1.jar
classes.zip 里面,就是dex文件
加载dex文件
示例代码
方式1:PathClassLoader
private void loadClassPathClassLoader() { //>android 8
try {
//app 内部的
Context context = getApplicationContext();
String dexDirectoryName = "dex"; // 存放DEX文件的子目录名称
File dexDirectory = context.getDir(dexDirectoryName, Context.MODE_PRIVATE);
String dexPath = new File(dexDirectory, "1.dex").getAbsolutePath(); // 替换为实际的DEX文件路径
//外部存储环境也可以实现
// dexPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/1.dex";
ClassLoader parentClassLoader = getClassLoader(); // 父类加载器
PathClassLoader pathClassLoader = new PathClassLoader(dexPath, parentClassLoader);
// 使用 dexPath 来加载和处理DEX文件
Class dogClazz = pathClassLoader.loadClass("test/Dog");
Class CatClazz = pathClassLoader.loadClass("test/Cat");
Object dog = dogClazz.getConstructors()[0].newInstance() ;
dogClazz.getMethod("eat").invoke(dog) ;
Object cat = CatClazz.getConstructors()[0].newInstance() ;
CatClazz.getMethod("eat").invoke(cat);
}catch (Exception e){
}
}
方式2:DexClassLoader
private void loadClassDexClassLoader(){
//app内部的
// String dexPath = outputFile.getAbsolutePath();
//外部存储环境
String dexPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/1.dex";
String optimizedPath = null ;
String librarySearchPath = null;
ClassLoader parentClassLoader = getClassLoader();
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, optimizedPath, librarySearchPath, parentClassLoader);
try {
// 使用 dexPath 来加载和处理DEX文件
Class dogClazz = dexClassLoader.loadClass("test/Dog");
Class CatClazz = dexClassLoader.loadClass("test/Cat");
Object dog = dogClazz.getConstructors()[0].newInstance() ;
dogClazz.getMethod("eat").invoke(dog) ;
Object cat = CatClazz.getConstructors()[0].newInstance() ;
CatClazz.getMethod("eat").invoke(cat);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
方式3:DexFile
private void loadClassDexFile() {//< android 8
try {
// 加载DEX文件
Context context = getApplicationContext();
String dexDirectoryName = "dex"; // 存放DEX文件的子目录名称
File dexDirectory = context.getDir(dexDirectoryName, Context.MODE_PRIVATE);
String dexPath = new File(dexDirectory, "1.dex").getAbsolutePath();
DexFile dexFile = new DexFile(dexPath); // 替换为实际的DEX文件路径
// 获取DEX文件中的类名列表
Enumeration<String> classNames = dexFile.entries();
// 搜索目标类名
String targetClassName = "test.Dog"; // 替换为目标类的完整类名
Class<?> targetClass = null;
while (classNames.hasMoreElements()) {
String className = classNames.nextElement();
if (className.equals(targetClassName)) {
targetClass = dexFile.loadClass(className, getClassLoader());
break;
}
}
if (targetClass != null) {
// 实例化目标类
Object targetInstance = targetClass.newInstance();
// 调用目标类的方法
Method targetMethod = targetClass.getDeclaredMethod("eat"); // 替换为目标方法名
targetMethod.setAccessible(true); // 如果方法是私有的,设置为可访问
targetMethod.invoke(targetInstance);
} else {
// 没有找到目标类
Log.d("Example", "Target class not found in DEX file");
}
} catch (Exception e) {
e.printStackTrace();
}
}
加载dex的3种方式的区别
相同点
PathClassLoader、DexClassLoader 都是通过DexFile类来实现类加载。
PathClassLoader、DexClassLoader 都会检测自己以及自己以上的类加载器是否已加载过这个类,如果已加载过,就直接将其返回,而不是重新加载;
3.PathClassLoader 和 DexClassLoader 类加载器都是继承自 BaseDexClassLoader
4.PathClassLoader 和 DexClassLoader 都能加载外部的 dex、jar、apk。
不同点
DexClassLoader 和 PathClassLoader 构造函数区别:参数optimizedDirectory的有无
optimizedDirectory 是经过优化的odex的路径。所谓odex,就是android软件中的classes.dex优化生成的odex文件,odex化即是把那个dex文件预先提取出来作用是能加快软件加载速度和开机速度。
android<8.0
DexClassLoader 可以指定 optimizedDirectory (即 dex2oat 的产物
.odex 存放的位置
),PathClassLoader 只能使用系统默认位置(optimizedDirectory)
BaseDexClassLoader
/**
@param dexPath:需要加载的文件列表 (文件可以是包含了 classes 和 resources 的 JAR、APK),多个文件用 “:” 分割。
@param optimizedDirectory:dex 经过 dex2oat 优化后,生成 .odex 文件的存放路径,可以为 null 。
@param libraryPath:存放需要加载的 native 库 (即.so库)的目录。
@param parent:父 ClassLoader。
通过构造函数我们大概可以了解到 BaseDexClassLoader 的运行方式,传入 dex 文件,然后进行优化,保存优化后的 dex 文件到 optimizedDirectory 目录。
**/
public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent);
// 这里将 optimizedDirectory 传入了 DexPathList 中。
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
}
DexClassLoader
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
// 此处将 optimizedDirectory 传入父类构造器中。
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
PathClassLoader
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String libraryPath, ClassLoader parent) {
// // 此处第二个参数代表 optimizedDirectory,传入null,使用默认的路径(即系统指定的路径)。
super(dexPath, null, libraryPath, parent);
}
}
DexPathList
如果optimizedDirectory 如果不存在,直接创建 DexFile 对象。否则通过dex文件和 optimizedDirectory路径加载DexFile对象
final class DexPathList {
// 省略代码
// 保存 dex 和资源列表
private final Element[] dexElements;
// 保存 .so 库
private final File[] nativeLibraryDirectories;
// 省略代码
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
// 省略代码
// 这里将 optimizedDirectory 传递给了 makeDexElements 方法。
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
// 省略代码
}
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions) {
// 将 optimizedDirectory 参数传递给 loadDexFile 方法
DexFile dex = loadDexFile(file, optimizedDirectory);
// 省略代码
}
private static DexFile loadDexFile(File file, File optimizedDirectory)
throws IOException {
if (optimizedDirectory == null) {
// optimizedDirectory 如果不存在,直接创建 DexFile 对象。
return new DexFile(file);
} else {
// 将dex/jar文件路径和输出目录转换为关联的优化dex文件的输出文件路径。
String optimizedPath = optimizedPathFor(file, optimizedDirectory);
// 将优化后的文件路径传入 DexFile 中。
return DexFile.loadDex(file.getPath(), optimizedPath, 0);
}
}
}
android>8.0
没有用到optimizedDirectory ,DexClassLoader 和 PathClassLoader 没区别
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent, boolean isTrusted) {
super(parent);
// optimizedDirectory 参数没有传递给 DexPathList。
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
if (reporter != null) {
reportClassLoaderChain();
}
}