在Android 5.0上动态加载DEX文件

时间:2014-12-07 23:24:09

标签: android classloader dex android-runtime dex2oat

在Android 5.0之前,我能够使用DexClassLoader动态加载DEX文件并调用loadClass()方法,但使用最新的Android版本,我得到ClassNotFoundException

这是我正在做的事情:

  1. 生成DEX文件。

    ../android-sdk/android-sdk-linux_86/build-tools/21.1.1/dx --dex --output=bin/output.dex  bin/output.jar
    
  2. 创建一个DexClassLoader。

    DexClassLoader cl = new DexClassLoader(
    dexFile.getAbsolutePath(),
    odexFile.getAbsolutePath(),
    null,
    mContext.getClassLoader());
    
  3. 致电cl.loadClass("myMethod");

  4. 我知道ART使用dex2oat来生成一个由ART加载的ELF文件,但在第2步中我生成了一个ODEX文件,因此我不需要在ART中运行以在运行时加载DEX文件,有谁可以帮助我?

2 个答案:

答案 0 :(得分:6)

更新

这适用于Dalvik和ART:new DexClassLoader(jarredDex.getAbsolutePath(), context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), null, context.getClassLoader());其中jarredDex是带有classes.dex的jar文件。可以通过运行dx --dex --output=filename.jar your/classes/dir来获取Jar。

原始答案

我从this article获取了代码示例。但ART使用PathClassLoader代替Dalvik的DexClassLoader。此代码在使用Android 6的模拟器和使用Android 5.1的小米上进行测试,并且工作正常:

// Before the secondary dex file can be processed by the DexClassLoader,
// it has to be first copied from asset resource to a storage location.
File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE), SECONDARY_DEX_NAME);
try (BufferedInputStream bis = new BufferedInputStream(getAssets().open(SECONDARY_DEX_NAME));
     OutputStream dexWriter = new BufferedOutputStream(new FileOutputStream(dexInternalStoragePath))) {

    byte[] buf = new byte[BUF_SIZE];
    int len;
    while((len = bis.read(buf, 0, BUF_SIZE)) > 0) {
        dexWriter.write(buf, 0, len);
    }
} catch (IOException e) {
    throw new RuntimeException(e);
}

try {
    PathClassLoader loader = new PathClassLoader(dexInternalStoragePath.getAbsolutePath(), getClassLoader());
    Class<?> toasterClass = loader.loadClass("my.package.ToasterImpl");
    Toaster toaster = (Toaster) toasterClass.newInstance();
    toaster.show(this, "Success!");
} catch (ReflectiveOperationException e) {
    throw new RuntimeException(e);
}

答案 1 :(得分:1)

这是制作dex文件的问题。如下更改命令,然后即可在所有版本的android中使用。

dx.bat --dex --output path/output.jar  path/input.jar

Windows中的上述方法将生成一个.jar文件,该jar文件中包含classes.dex文件。 DexClassLoader在内部搜索classes.dex文件,这就是为什么它抛出ClassNotFoundException