How to load a Java class dynamically on android/dalvik?
Asked Answered
M

1

33

I'm wondering if and how one can load dex or class files dynamically in dalvik, some quick'n'dirty test function I wrote was this:

    public void testLoader() { 
            InputStream in; 
            int len; 
            byte[] data = new byte[2048]; 
            try { 
                    in = context.getAssets().open("f.dex"); 
                    len = in.read(data); 
                    in.close(); 
                    DexFile d; 
                    Class c = defineClass("net.webvm.FooImpl", data, 0, len); 
                    Foo foo = (Foo)c.newInstance(); 
            } catch (IOException e1) { 
                    // TODO Auto-generated catch block 
                    e1.printStackTrace(); 
            } catch (IllegalAccessException e) { 
                    // TODO Auto-generated catch block 
                    e.printStackTrace(); 
            } catch (InstantiationException e) { 
                    // TODO Auto-generated catch block 
                    e.printStackTrace(); 
            } 
    } 

whereas the Foo interface is this

    public interface Foo { 
            int get42(); 
    } 

and f.dex contains some dx'ed implementation of that interface:

    public class FooImpl implements Foo { 
            public int get42() { 
                    return 42; 
            } 
    } 

The above test driver throws at defineClass() and it doesn't work and I investigated the dalvik code and found this:

http://www.google.com/codesearch/p?hl=en#atE6BTe41-M/vm/Jni.c&q=Jni.c...

So I'm wondering if anyone can enlighten me if this is possible in some other way or not supposed to be possible. If it is not possible, can anyone provide reasons why this is not possible?

Mithridate answered 11/6, 2010 at 11:53 Comment(7)
You have DexFile d, then never assign or use it. AFAIK, DexClassLoader is the correct approach, though I haven't used it personally.Handtohand
That's true, the DexFile is some remainder of another dirty hack I tried, I'll look into DexClassLoader now.Mithridate
I tried using DexClassLoader, but that doesn't work either. I created a derived class and called the superconstructor with super("/sdcard/f.jar", "/sdcard", null, getSystemClassLoader()); But no success. Wether defineClass nor findClass return any class that is attached dynamically. My suspect is that android does not support this at all, otherwise normal defineClass should work already. Probably because of some security issues. But I'd definately like to hear reasons, I also started a thread on android-developers Google group.Mithridate
DexClassLoader works, as illustrated by dalvik/tests/068-classloader in the source tree. It's used by apps that want a "plugin" architecture. Bear in mind that the class is only visible by going through the custom class loader.Modillion
Maybe PathClassLoader is better: #2903760Mapping
Look at: #5105323Mapping
Could you plese replace google.com/codesearch/p?hl=en#atE6BTe41-M/vm/Jni.c&q=Jni.c as it is broken ?Lindeberg
V
53

There's an example of DexClassLoader in the Dalvik test suite. It accesses the classloader reflectively, but if you're building against the Android SDK you can just do this:

String jarFile = "path/to/jarfile.jar";
DexClassLoader classLoader = new DexClassLoader(
    jarFile, "/tmp", null, getClass().getClassLoader());
Class<?> myClass = classLoader.loadClass("MyClass");

For this to work, the jar file should contain an entry named classes.dex. You can create such a jar with the dx tool that ships with your SDK.

Valve answered 11/6, 2010 at 15:55 Comment(8)
Replace "/tmp" with something else on the device.Modillion
dx.bat --dex --output=E:\classes.dex E:\test_app.jarMapping
That's a lot better than the build.xml tweaks in android-developers.blogspot.com/2011/07/… - but is there a way to have Eclipse do the dx step on every build?Bever
I have a question: How do you unload what you've loaded?Ulric
@androiddeveloper there is no way to unload a class in java.Wb
@Wb you can only load new classes? what if (as an alternative) I try to load from a file that already has the same package and class name, and have an empty implementation inside the class? is it possible? will it minimize the memory being used as I don't need the real loaded class anymore?Ulric
@androiddeveloper, I don'T think it can work, but please try. Maybe you could also have a look at ActivityTestCase source code, there is a scrubClass method that may help. grepcode.com/file/repository.grepcode.com/java/ext/…Wb
@Wb Interesting. Sadly I can't do it right now, as I have an army-draft (I'm from Israel), so I hope to remember to get back to this some time in the future. thank you.Ulric

© 2022 - 2024 — McMap. All rights reserved.