Load DEX file dynamically on Android 5.0
Asked Answered
C

2

15

Prior to Android 5.0 I was able to load DEX files dynamically using DexClassLoader and calling loadClass() method but with the latest Android version I get a ClassNotFoundException.

Here is what I am doing:

  1. Generate DEX file.

    ../android-sdk/android-sdk-linux_86/build-tools/21.1.1/dx --dex --output=bin/output.dex  bin/output.jar
    
  2. Create a DexClassLoader.

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

I am aware that ART uses dex2oat to generate an ELF file that is the loaded by ART but in step 2 I am generating an ODEX file so I am not what needs to be done in ART to load a DEX file at runtime, can anyone help me ?

Concerned answered 7/12, 2014 at 23:24 Comment(6)
Why do you need to load a DEX file at runtime? 5.0 supports multiple dex files natively.Yahoo
The DEX file has sensitive information and it is encrypted in the assets directory. When I need to use it, it is decrypted and then loaded at runtime.Concerned
@Concerned have you managed to resolve this issue? I'm having the same problem, this only works on Dalvik for me.Tooling
Any news here? I'd assume that it's not possible to load dynamic code on newer Android versions anymore (missing OpenDEXfile(byte[] ...). Does anyone know a different solution?Celina
naturally same issue on android6 marshmallow. i think injecting code runtime very important concept like plug-in based app and not just related to multidex problem. It's sad couldn't find any solution on the internet about itGoodnatured
One approach – the only one that I know to be supported – is to write the dynamic code as native ARM machine code with the help of a library like LLVM, and load it at runtime. So drop to NDK.Stake
S
6

Update

This works both on Dalvik and ART: new DexClassLoader(jarredDex.getAbsolutePath(), context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), null, context.getClassLoader()); where jarredDex is a jar-file with classes.dex. Jar can be obtained by running dx --dex --output=filename.jar your/classes/dir.


Original answer

I've took a code sample from this article. But ART uses PathClassLoader instead of Dalvik's DexClassLoader. This code is tested on emulator with Android 6 and on Xiaomi with Android 5.1 and works fine:

// 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);
}
Stanleystanly answered 21/10, 2016 at 14:37 Comment(1)
Can you please help out in this - #67668327Newsboy
B
3

It is the problem with making dex file. Change the command as below then will work in all versions of android.

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

The above method in windows will generate a .jar file with classes.dex file inside that jar file. The DexClassLoader is searching for classes.dex file inside, that is why it is throwing ClassNotFoundException

Beatrice answered 9/8, 2018 at 5:18 Comment(1)
Can you please have a look at my query - #67668327Newsboy

© 2022 - 2024 — McMap. All rights reserved.