2010-03-25 49 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