本文記述“柯元旦”Android核心剖析中基於類裝載器的“外掛程式”架構。
外掛程式的概念:
1、外掛程式不能獨立運行,而必須運行於一個宿主程式中,即由宿主程式去調用外掛程式程式。
2、外掛程式一般可以獨安裝。
3、宿主程式中可以管理不同的外掛程式,包括查看外掛程式的數目,禁用或者使用某個外掛程式。
4、宿主程式應該保證外掛程式的向下相容性,即新版本的宿主程式可以運行較老版本的外掛程式。
下面詳細看一下這種架構:
1、宿主程式:
建立Android項目PluginDevAndroid
2、外掛程式項目1:Plugin1
3、外掛程式項目2:
4、綜述:
4.1、介面類一般定義在宿主專案中,比如本例中的IPluginDev.java
4.2、外掛程式項目需要應用IPluginDev時,則必須通過一個外部的jar包,並且該jar包是以Library的形式被添加到Plugin項目的build Path,而不是以“外部的”jar方式添加。
4.3、宿主程式想要知道系統中有哪些外掛程式,可以定義一個Action,本例中使用的是如下action。
這樣的話,宿主程式就可以通過PackageManager類的queryIntentActivities函數查詢相關的外掛程式的列表了。
得到了外掛程式的PackageName,就可以訪問外掛程式的資源內容。例如:
Resources res = pm.getResourcesForApplication(packageName);int id = 0;id = res.getIdentifier(version, string, packageName);String version = res.getString(id);Log.d(hlwang, MainActivity test version is:+version);
這段代碼中,首先擷取外掛程式的Resource對象,接著得到名稱為version欄位的字串id值,然後再調用getString獲得該變數的值,於是宿主程式就知道外掛程式程式中的資源內容了。
關鍵代碼:
private void test(){Intent intent = new Intent(com.example.plugindevandroid.plugin,null);final PackageManager pm = getPackageManager();final List plugins = pm.queryIntentActivities(intent, 0);for(ResolveInfo r:plugins){ActivityInfo activityInfo = r.activityInfo;String div = System.getProperty(path.separator);String packageName = activityInfo.packageName;String packageName0 = getPackageName();String dexPath = activityInfo.applicationInfo.sourceDir;String dexOutputDir1 = activityInfo.applicationInfo.dataDir;String dexOutputDir2 = getApplicationInfo().dataDir;String libPath = activityInfo.applicationInfo.nativeLibraryDir;Log.d(hlwang, MainActivity test div is:+div+,packageName is:+packageName+,packageName0 is:+packageName0+,dexPath is:+dexPath+,dexOutputDir1 is:+dexOutputDir1+,dexOutputDir2 is:+dexOutputDir2+,libPath is:+libPath);DexClassLoader dexCl = new DexClassLoader(dexPath, dexOutputDir2, libPath, getClassLoader());Log.d(hlwang, MainActivity test clazzName is:+packageName+.PluginVersion);try{Class clazz = dexCl.loadClass(packageName+.PluginVersion);IPluginDev plugin = (IPluginDev) clazz.newInstance();String name = plugin.getName();Log.d(hlwang, MainActivity test name is:+name);Resources res = pm.getResourcesForApplication(packageName);int id = 0;id = res.getIdentifier(version, string, packageName);String version = res.getString(id);Log.d(hlwang, MainActivity test version is:+version);PluginObject p = new PluginObject();p.name = name;p.version = version;Log.d(hlwang, MainActivity test p is:+p);mList.add(p);}catch(Exception e){Log.d(hlwang, MainActivity exception eeeeeeeeeeeee);e.printStackTrace();}}Log.d(hlwang, MainActivity test list size is:+mList.size());setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, mList));}這段代碼中,首先得到外掛程式的List列表。
然後得到外掛程式的packageName,以及外掛程式的dexPath目錄。
再次,得到dexOutputDir目錄。
libPath一般只c/c++使用的庫檔案。
DexClassLoader的參數意義:
dexPath:外掛程式apk或者jar包檔案的路徑
dexOutputDir:將目標apk或者jar包解壓的檔案的存放目錄。因為宿主程式只對本應用程式所在的目錄由存取許可權。
運行: