基于插件开发的Android实现流程
转载请注明地址:http://blog.****.net/droyon/article/details/20951797
本文记述“柯元旦”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);
关键代码:
- private void test(){
- Intent intent = new Intent("com.example.plugindevandroid.plugin",null);
- final PackageManager pm = getPackageManager();
- final List<ResolveInfo> 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<PluginObject>(this,
- android.R.layout.simple_list_item_1, mList));
- }
然后得到插件的packageName,以及插件的dexPath目录。
再次,得到dexOutputDir目录。
libPath一般只c/c++使用的库文件。
DexClassLoader的参数意义:
dexPath:插件apk或者jar包文件的路径
dexOutputDir:将目标apk或者jar包解压的文件的存放目录。因为宿主程序只对本应用程序所在的目录由存取权限。
运行截图: