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]]

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
node_analyser
  • 1,502
  • 3
  • 17
  • 34
  • AFAIK, ART does not support classes within default package (i. e. without `package` directive). – Miha_x64 May 27 '21 at 20:29
  • @Miha_x64 - 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. – node_analyser May 28 '21 at 04:56
  • Can you show full exception message, please? – Miha_x64 May 28 '21 at 21:41
  • @Miha_x64 - I have included both exceptions in edits. First exception is without package name. Second exception is when I included package name. – node_analyser May 29 '21 at 06:47
  • @Miha_x64 - 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. – node_analyser May 29 '21 at 06:50
  • Wait, why are you using DexClassLoader, not PathClassLoader as I've suggested in https://stackoverflow.com/a/40179430/3050249? – Miha_x64 May 29 '21 at 14:23
  • 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. – node_analyser May 29 '21 at 17:23
  • I am having a look at link shared above by you. In meantime, I also tried this article https://programmer.help/blogs/android-dynamically-loads-apk-plug-in-classes.html . Tried each and every step successfully but again same `ClassNotFound` exception at the end. :'( – node_analyser May 29 '21 at 17:26
  • @Miha_x64 - 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. – node_analyser May 29 '21 at 17:39
  • You're using File.separator instead of File.pathSeparator. – Miha_x64 May 29 '21 at 19:57

0 Answers0