再议模块化设计
先前的文档有提及过2种针对****安装包过大的功能剥离和拆分的方案:以前(1)把需要剥离的功能逻辑使用jar报读方式剥离,并通过DexClassloader方式来加载;(2) 使用SL4A的方式来实现;现在例外介绍一种,按照界面和功能来拆分****.然后把这个功能创建成一个apk,通过sharedUserId的方式将子功能apk和主程序联系在一起,并且运行在同一个进程中,资源等共享.
android下,默认的情况是,每个apk相互独立的,基本上每个应用都是一个dalvik虚拟机,都有一个uid,如果多个apk共用一个uid话,就可以作为一个独立应用的集成,运行在一个单独的dalvik虚拟机.配置代码如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:sharedUserId="com.nd.android.pandareader"
package="com.nd.android.pandareader" android:versionCode="2600" android:versionName="2.6">
...
</manifest>
那这样子就需要在****加载的是否把相同配置的apk检索出来,并加载到应用中.如下代码:
//遍历包名,来获取插件
PackageManager pm=getPackageManager();
List<PackageInfo> pkgs=pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
for(PackageInfo pkg : pkgs){
//包名
String packageName=pkg.packageName;
String sharedUserId= pkg.sharedUserId;
//sharedUserId是开发时约定好的,这样判断是否为自己人 if(!"com.android".equals(sharedUserId)||"com.android".equals(packageName)){
//相同sharedUserId的apk
...
}
}
主程序还可以通过侦听packgeManager的安装完成广播,在****的运行期来动态的加载新更新的插件apk包。
这种方式插件apk包被设计成<category android:name="android.intent.category.DEFAULT" />所以不会在桌面的应用程序列表中显现,但是会系统的已下载应用列表中显示,所以这样子,在拆分构功能的时候就需要一些技巧,比如把能够独自成一个应用的功能拆分出来,例如文件列表,wifi传送等.一方面也为机子提供这样的应用,另一方面为****做技术支撑.
在拆分功能之后,还需要就规定这些功能模块的描述,以使得主程序能够找到这些功能模块,并且在这些的模块中抽象出接口,以便方便的调用.因为属于同一个进程,所以在主程序中很方便的利用下面的代码来创建功能模块的上下文,通过描述性文件和抽象的接口就能直接运行功能模块(测试中直接用invoke来调用).
try{
Context pkgContext=createPackageContext(pkg.packageName,
Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY);
Class clazz=pkgContext.getClassLoader().loadClass("com.android.uid_1.UidSun1Activity");
Activity activity=(Activity)clazz.newInstance();
Method m=clazz.getMethod("setText", String.class);
m.invoke(activity, "****子程序调用测试用例");
}catch(Exception e){
}