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
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
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
.
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);
}