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 ?

Jonas Czech
  • 12,018
  • 6
  • 44
  • 65
garibay
  • 1,046
  • 1
  • 10
  • 12
  • Why do you need to load a DEX file at runtime? 5.0 supports multiple dex files natively. – ianhanniballake Dec 07 '14 at 23:55
  • 2
    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. – garibay Dec 08 '14 at 15:24
  • 1
    @garibay have you managed to resolve this issue? I'm having the same problem, this only works on Dalvik for me. – cdroid Jun 07 '15 at 15:34
  • 1
    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? – Nils Jan 29 '16 at 11:36
  • 1
    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 it – gturedi Mar 18 '16 at 20:21
  • 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. – Demi Oct 15 '16 at 22:51

2 Answers2

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);
}
Miha_x64
  • 5,973
  • 1
  • 41
  • 63
  • Can you please help out in this - https://stackoverflow.com/questions/67667827/classnotfound-exception-while-dynamically-loading-dex-file-in-android – node_analyser May 27 '21 at 18:23
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

Vaishakh
  • 1,126
  • 10
  • 10
  • Can you please have a look at my query - https://stackoverflow.com/questions/67667827/classnotfound-exception-while-dynamically-loading-dex-file-in-android – node_analyser May 27 '21 at 18:23