"ClassNotFound" Exception while dynamically loading .dex file in Android
Asked Answered
B

0

1

I am trying to learn dynamically loading classes (.dex/.jar) in Android. I assembled the basic ideas from tutorials and Stack Overflow questions (tutorial, this, and this), but I am failing to fulfill my purpose of dynamically loading class files and constantly giving the ClassNotFound exception.

My steps in brief:

  1. Created a Java file as given in the article.

     public class DynamicClass {
         public static void main(String[] args){
             print();
         }
    
         public static void print() {
             System.out.println("Hello Dynamic");
         }
     }
    
  2. Converted java source to .class (result = DynamicClass.class)

     javac DynamicClass.java
    
  3. Created jar file using dx tool from Android SDK. (result = dynamic.jar with classes.dex in it)

     dx --dex --output=dynamic.jar DynamicClass.class
    

    Once I got the .jar file, I pushed it to /sdcard/ (tested on both, emulator as well as device)

    Emulator : Android 6.0 and Device : Android 11.0

    Brief code for loading the class:

     try {
             String dexPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dynamic.jar";
             Log.d("DYNAMIC_TEST","dexPath: "+dexPath);
             final File tmpDir = getDir("dex", 0);
    
             // temporary file creation for .exists() check
             File dexFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dynamic.jar");
    
             if (dexFile.exists()){ // dexFile location is same as dexPath location
                 Log.d("DYNAMIC_TEST", "File Found");
                 DexClassLoader dexClassLoader = new DexClassLoader(dexPath,
                         tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
    
                 Class dynamicClass = dexClassLoader.loadClass("DynamicClass");
                 Method printMethod = dynamicClass.getMethod("print");
                 printMethod.invoke(dynamicClass.newInstance());
                 Log.d("DYNAMIC_TEST","Success");
             }
             else {
                 Log.d("DYNAMIC_TEST", "File NOT Found");
             }
    
         }catch (Exception e){
             Log.d("DYNAMIC_TEST", "Exception: "+ e.toString());
         }
    

I am constantly getting the ClassNotFound Exception.

What am I missing? Why is it that am not able to load this simple class file :(?

My checklist:

  1. Made sure that code is able to get the loaded file (<File>.exists()). Code is able to get the file. Only not able to load the class.
  2. Made sure dynamic.jar contains a classes.dex entry inside it. (This is because DexClassLoader wants a .jar/.apk file with the classes.dex entry in it)
  3. Tried running code on emulator as well as device (both having different Android versions).

Exception description:

Exception: java.lang.ClassNotFoundException: Didn't find class "DynamicClass" on path: DexPathList[[zip file "/storage/emulated/0/dynamic.jar"],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]

Exception after including package.

Exception: java.lang.ClassNotFoundException: Didn't find class "mypack.DynamicClass" on path: DexPathList[[zip file "/storage/emulated/0/mypack.jar"],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]

Bibliotheca answered 24/5, 2021 at 6:58 Comment(10)
AFAIK, ART does not support classes within default package (i. e. without package directive).Heiduc
@Heiduc - I just tried keeping DynamicClass.java inside a directory named mypack and also modified java file including package mypack;. Inside DexClassLoader changed the call to mypack.DynamicClass instead of just DynamicClass but still the exception stays.Bibliotheca
Can you show full exception message, please?Heiduc
@Heiduc - I have included both exceptions in edits. First exception is without package name. Second exception is when I included package name.Bibliotheca
@Heiduc - How did I use package name ? Created a directory named mypack. -- moved DynamicClass.java into mypack. -- added package mypack; in java file and then compiled.Bibliotheca
Wait, why are you using DexClassLoader, not PathClassLoader as I've suggested in https://mcmap.net/q/245644/-load-dex-file-dynamically-on-android-5-0?Heiduc
Upto my understanding, I think PathClassLoader is to be used when loading jar from internal storage and DexClassLoader is to be used for loading jar from location other than app's internal storage. Please correct me if I have misunderstood anything here.Bibliotheca
I am having a look at link shared above by you. In meantime, I also tried this article programmer.help/blogs/… . Tried each and every step successfully but again same ClassNotFound exception at the end. :'(Bibliotheca
@Heiduc - I revisited your answer and noticed that you are loading jar from app's internal storage. Loading it from assets directory and hence using PathClassLoader. In my use-case, I want to load app from sdcard and hence am using DexClassLoader. And therefore, I went with your answer's Update section code.Bibliotheca
You're using File.separator instead of File.pathSeparator.Heiduc

© 2022 - 2024 — McMap. All rights reserved.