在Android 5.0上动态加载DEX文件

gar*_*bay 15 android classloader dex android-runtime dex2oat

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

这是我在做的事情:

  1. 生成DEX文件.

    ../android-sdk/android-sdk-linux_86/build-tools/21.1.1/dx --dex --output=bin/output.dex  bin/output.jar
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个DexClassLoader.

    DexClassLoader cl = new DexClassLoader(
    dexFile.getAbsolutePath(),
    odexFile.getAbsolutePath(),
    null,
    mContext.getClassLoader());
    
    Run Code Online (Sandbox Code Playgroud)
  3. 呼叫 cl.loadClass("myMethod");

我知道ART使用dex2oat来生成一个由ART加载的ELF文件但是在步骤2中我生成了一个ODEX文件,因此我不需要在ART中运行以在运行时加载DEX文件,任何人都可以帮助我 ?

Mih*_*x64 6

更新

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


原始答案

我从这篇文章中获取了一个代码示例.但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);
}
Run Code Online (Sandbox Code Playgroud)