【问题标题】:Android, how to use DexClassLoader to dynamically replace an Activity or ServiceAndroid,如何使用DexClassLoader动态替换一个Activity或Service
【发布时间】:2011-01-31 23:06:24
【问题描述】:

我正在尝试做类似stackoverflow posting 的事情。我想做的是从 SD 卡中读取活动或服务的定义。为避免清单权限问题,我在 .apk 中创建了此活动的 shell 版本,但尝试将其替换为运行时驻留在 SD 卡上的同名活动。不幸的是,我可以使用 DexClassLoader 从 SD 卡加载活动类定义,但执行的是原始类定义。有没有办法指定新的类定义替换旧的类定义,或者有什么建议可以避免清单权限问题而不实际在包中提供所需的活动?代码示例:

    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) {

在启动/sdcard/mypath/My.apk 中指定的com.android.my.path.to.a.loaded.activity 后,它会启动静态加载到项目中的活动。

【问题讨论】:

  • 我有一种感觉,这不能仅仅因为 Android 处理资产的方式。如果您在另一个应用程序中的一个类上调用 startActivity,它必须加载到该应用程序的线程而不是您自己的线程中,因此只是一个危险的 Android Intent 替代方案。

标签: android auto-update


【解决方案1】:

通过 DexClassLoader 启动一个 Activity 会很棘手,因为你没有安装 APK,所以没有什么可以处理你的 Intent。

您的平台 APK 中应该有相同的活动类,并在 AndroidManifest.xml 中声明它。然后,您应该将当前的 ClassLoader 更改为您想要的 DexClassLoader。结果,它将启动您的插件 APK。 (注:“平台APK”是指手机中已经安装的应用程序,“插件APK”是指SD卡中保存的apk文件。)

平台的应用程序应如下所示:

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);
    }
}

更多代码,可以访问https://github.com/Rookery/AndroidDynamicLoader

我正在阅读 Android 源代码,以便找到一种更优雅的方法来实现此功能。如果您有任何想法,请随时与我联系。

【讨论】:

  • 您的回答非常棒 +1。这让我很开心。
  • 很好的答案!该链接对我帮助很大。
  • 这里最好解释一下史密斯班。
  • Smith 是一个反射辅助类。
  • @simpleton 您是否尝试过其中任何一种,因为我尝试过其中大多数都出现了不同的错误。你能帮我看看你尝试过的还是你的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 1970-01-01
相关资源
最近更新 更多