19

I am trying to do something similar to this stackoverflow posting. What I want to do is to read the definition of an activity or service from the SD card. To avoid manifest permission issues, I create a shell version of this activity in the .apk, but try to replace it with an activity of the same name residing on the SD card at run time. Unfortunately, I am able to load the activity class definition from the SD card using DexClassLoader, but the original class definition is the one that is executed. Is there a way to specify that the new class definition replaces the old one, or any suggestions on avoiding the manifest permission issues without actually providing the needed activity in the package? The code sample:

    ClassLoader cl = new DexClassLoader("/sdcard/mypath/My.apk",
            getFilesDir().getAbsolutePath(),
            null,
            MainActivity.class.getClassLoader());

    try {
        Class<?> c = cl.loadClass("com.android.my.path.to.a.loaded.activity");
        Intent i = new Intent(getBaseContext(), c);
        startActivity(i);
    }
    catch (Exception e) {

Intead of launching the com.android.my.path.to.a.loaded.activity specified in /sdcard/mypath/My.apk, it launches the activity statically loaded into the project.

Community
  • 1
  • 1
RickNotFred
  • 3,381
  • 2
  • 24
  • 26
  • I have a feeling that this cannot be done simply because of how Android handles assets. If you called startActivity on a class in another application it would have to load in that application's thread not your own, and thus be simply a dangerous alternative to Android's Intents. – Tom Aug 01 '11 at 03:42

1 Answers1

18

Starting an Activity through DexClassLoader will be very tricky, because you didn't install the APK, and so there is nothing to handle your Intent.

You should have the same activity class in your platform APK and declare it in AndroidManifest.xml. Then, you should change the current ClassLoader to your desired DexClassLoader. As a result, it will start your plugin APK. (Note: "platform APK" refers to the app that is already installed in the phone, whereas "plugin APK" refers to the apk file saved in your SD card.)

The platform's application should look something like this:

public static ClassLoader ORIGINAL_LOADER;
public static ClassLoader CUSTOM_LOADER = null;

@Override
public void onCreate() {
    super.onCreate();
    try {
        Context mBase = new Smith<Context>(this, "mBase").get();

        Object mPackageInfo = new Smith<Object>(mBase, "mPackageInfo")
                .get();
        //get Application classLoader
        Smith<ClassLoader> sClassLoader = new Smith<ClassLoader>(
                mPackageInfo, "mClassLoader");
        ClassLoader mClassLoader = sClassLoader.get();
        ORIGINAL_LOADER = mClassLoader;

        MyClassLoader cl = new MyClassLoader(mClassLoader);
        //chage current classLoader to MyClassLoader
        sClassLoader.set(cl);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

class MyClassLoader extends ClassLoader {
    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    public Class<?> loadClass(String className)
            throws ClassNotFoundException {
        if (CUSTOM_LOADER != null) {
            try {
                Class<?> c = CUSTOM_LOADER.loadClass(className);
                if (c != null)
                    return c;
            } catch (ClassNotFoundException e) {
            }
        }
        return super.loadClass(className);
    }
}

For more code, you can visit https://github.com/Rookery/AndroidDynamicLoader

I'm reading the Android source code in order to find a more elegant method to implement this feature. If you have any idea, feel free to contact me.

rdb
  • 1,488
  • 1
  • 14
  • 24
Sim Sun
  • 587
  • 1
  • 4
  • 28
  • Your answer is awesome +1 for it. This makes my day. – Krypton Apr 10 '13 at 09:02
  • great answer !! the link helped me a lot. – qiuping345 Feb 12 '14 at 08:03
  • 1
    It's better if you explain the class Smith here. – k__gc_im_o_ Sep 13 '14 at 13:34
  • Smith is a helper class for reflecting. – Sim Sun Oct 21 '14 at 16:33
  • @simpleton Did find any better solution and the solution which you have given.I have gone throught the github project and tried myself but it shows the package activity rather than the activity in the apk – Sai Krishna May 02 '16 at 10:51
  • @SaiKrishna my repo is the very simple demo for learning how to implement dynamic loading. There are several better repos in github. You can choose one in https://github.com/liaohuqiu/android-dynamic-load-awesome – Sim Sun May 04 '16 at 15:17
  • 1
    @simpleton have you tried any of those,as I tried most of them got different errors. Can you help me with the one which you have tried or yours? – Sai Krishna May 04 '16 at 20:10
  • can we declare permission on "Plugin APK" instead of "Platfrom APK"? – Cuong Vo Oct 22 '19 at 07:42
  • If this works (it does) it is extremely impractical to be of any use. It's unfortunate. –  Jun 18 '21 at 19:09