2010-03-25 71 views
16

我正在尝试做类似于stackoverflow posting的操作。我想要做的是从SD卡上读取活动或服务的定义。为避免出现明显的权限问题,我在.apk中创建了此活动的shell版本,但尝试在运行时将其替换为存储在SD卡上的同名活动。不幸的是,我可以使用DexClassLoader从SD卡加载活动类定义,但原始类定义是执行的。有没有一种方法可以指定新的类定义替换旧的定义,或者在没有实际提供包中所需的活动的情况下避免出现清单权限问题的任何建议?代码示例:Android,如何使用DexClassLoader动态替换活动或服务

发动 /sdcard/mypath/My.apk指定的 com.android.my.path.to.a.loaded.activity
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) { 

这一翻译,它会启动静态加载到项目活动。

+0

我有一种感觉,这不能简单地完成,因为Android如何处理资产。如果您在另一个应用程序的类中调用了startActivity,它将不得不加载该应用程序的线程,因此它只是Android Intents的一个危险的替代方案。 – Tom 2011-08-01 03:42:18

回答

13

通过DexClassLoader开始活动将非常棘手,因为您没有安装APK,所以没有任何东西可以处理您的意图。

您应该在平台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源代码,以便找到实现该功能的更优雅的方法。如果您有任何想法,请随时与我联系。

+0

你的答案是非常棒的+1。这使我的一天。 – Krypton 2013-04-10 09:02:13

+0

伟大的答案!该链接帮助了我很多。 – qiuping345 2014-02-12 08:03:45

+1

如果你在这里解释史密斯班,那会更好。 – 2014-09-13 13:34:30