Starting an Activity using DexClassLoader

797 views Asked by At

My requirement is to start an Activity which is present in an aar file inside your asset folder or may be in SDCard. But I am getting below exception:

01-05 21:06:18.717 3150-3150/com.example.nayakc2.dynamicloading W/System.err: java.lang.ClassNotFoundException: Didn't find class "com.example.nayakc2.aarsample.LibActivity" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib, /vendor/lib]]
01-05 21:06:18.717 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
01-05 21:06:18.717 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
01-05 21:06:18.717 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
01-05 21:06:18.717 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at com.example.nayakc2.dynamicloading.MainActivity.startActivityFromAar(MainActivity.java:70)
01-05 21:06:18.719 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at com.example.nayakc2.dynamicloading.MainActivity.onOptionsItemSelected(MainActivity.java:56)
01-05 21:06:18.720 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.app.Activity.onMenuItemSelected(Activity.java:3204)
01-05 21:06:18.720 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:408)
01-05 21:06:18.720 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:198)
01-05 21:06:18.721 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:113)
01-05 21:06:18.721 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:113)
01-05 21:06:18.721 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:69)
01-05 21:06:18.721 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:206)
01-05 21:06:18.721 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:776)
01-05 21:06:18.721 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:822)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:156)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:969)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.view.menu.MenuPopup.onItemClick(MenuPopup.java:127)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.widget.AdapterView.performItemClick(AdapterView.java:310)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.widget.AbsListView.performItemClick(AbsListView.java:1155)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.widget.AbsListView$PerformClick.run(AbsListView.java:3120)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.widget.AbsListView.onTouchUp(AbsListView.java:4047)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.widget.AbsListView.onTouchEvent(AbsListView.java:3806)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.support.v7.widget.ListViewCompat.onTouchEvent(ListViewCompat.java:124)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.View.dispatchTouchEvent(View.java:9943)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2663)
01-05 21:06:18.722 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2344)
01-05 21:06:18.723 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
01-05 21:06:18.723 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2358)
01-05 21:06:18.723 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
01-05 21:06:18.723 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2358)
01-05 21:06:18.723 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.widget.PopupWindow$PopupDecorView.dispatchTouchEvent(PopupWindow.java:2266)
 01-05 21:06:18.724 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.View.dispatchPointerEvent(View.java:10163)
01-05 21:06:18.724 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4434)
01-05 21:06:18.726 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4302)
01-05 21:06:18.726 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3849)
01-05 21:06:18.726 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3902)
01-05 21:06:18.726 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3868)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3995)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3876)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4052)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3849)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3902)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3868)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3876)
01-05 21:06:18.727 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3849)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6210)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6184)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6145)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6313)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.os.MessageQueue.nativePollOnce(Native Method)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.os.MessageQueue.next(MessageQueue.java:323)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.os.Looper.loop(Looper.java:136)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6077)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
01-05 21:06:18.728 3150-3150/com.example.nayakc2.dynamicloading W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

Here is my code to achieve this:

private void startActivityFromAar() {
File file = new File("file:///android_asset/sample.aar");
DexClassLoader dexLoader = new DexClassLoader(file.getAbsolutePath(),
        getCacheDir().getAbsolutePath(), null, getClassLoader());
setAPKClassLoader(dexLoader);

try {
    Class<?> activityClass = dexLoader.loadClass("com.example.nayakc2.aarsample.LibActivity");
    Intent intent = new Intent(this, activityClass);
    startActivity(intent);
} catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
}

private void setAPKClassLoader(ClassLoader classLoader)
{
try {
    Field mMainThread = getField(Activity.class, "mMainThread");
    Object mainThread = mMainThread.get(this);
    Class threadClass = mainThread.getClass();
    Field mPackages = getField(threadClass, "mPackages");

    Map<String,?> map = (Map<String,?>) mPackages.get(mainThread);
    WeakReference<?> ref = (WeakReference<?>) map.get(getPackageName());
    Object apk = ref.get();
    Class apkClass = apk.getClass();
    Field mClassLoader = getField(apkClass, "mClassLoader");

    mClassLoader.set(apk, classLoader);
} catch (IllegalArgumentException | IllegalAccessException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
}

private Field getField(Class<?> cls, String name)
{
for (Field field: cls.getDeclaredFields())
{
    if (!field.isAccessible()) {
        field.setAccessible(true);
    }
    if (field.getName().equals(name)) {
        return field;
    }
}
return null;
}

Where do I do mistake? Any help is greatly helpful.

1

There are 1 answers

11
CommonsWare On

My requirement is to start an Activity which is present in an aar file inside your asset folder or may be in SDCard.

That is not going to be practical in general.

Where do I do mistake?

First, an asset is a file on your development machine. It is not a file on the device. file:///android_asset/ is usable in a WebView, but not in general.

Second, you are assuming that your reflection will work across all the devices that you are going to support. At best, this approach works when you are in control over the hardware.

Third, the activity will not be in the manifest, unless you somehow arranged for that yourself when you built your main app.

Fourth, the activity will not have access to the resources in the AAR, such as the resources that it was compiled against. It will attempt to load those resources from your main app, and most likely those resources have different ID values.