转-基于插件开发的Android实现流程
原始地址: http://www.2cto.com/kf/201403/284689.html
本文记述“柯元旦”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,就可以访问插件的资源内容。例如:
1
2
3
4
5
|
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获得该变量的值,于是宿主程序就知道插件程序中的资源内容了。
关键代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
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)); }</pluginobject></resolveinfo> |
这段代码中,首先得到插件的List列表。
然后得到插件的packageName,以及插件的dexPath目录。
再次,得到dexOutputDir目录。
libPath一般只c/c++使用的库文件。
DexClassLoader的参数意义:
dexPath:插件apk或者jar包文件的路径
dexOutputDir:将目标apk或者jar包解压的文件的存放目录。因为宿主程序只对本应用程序所在的目录由存取权限。
运行截图:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。