1)类转载器ClassLoader:
标准的javaSDK中有ClassLoader类,ClassLoader 加载类的方式常称为双亲委托,ClassLoader.java 具体代码如下:
protectedClass>loadClass(StringclassName,booleanresolve)throwsClassNotFoundException{
Class>clazz=findLoadedClass(className);
clazz=parent.loadClass(className,false);
}catch(ClassNotFoundExceptione){
clazz=findClass(className);
loadClass 会先看这个类是不是已经被 loaded 过,没有的话则去他的 parent 去找,如此递归,称之为双亲委托。
在Android中可以动态加载,但无法像Java中那样方便动态加载jar。原因:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byteCode,需要通过dx工具来优化转换成Dalvik byteCode才行。项目中,引入其他Jar的内容都被打包进了classes.dex。dex文件是Android系统将所需要的所有Class文件重新打包,打包时并进行了优化。
DexClassLoader
可以加载jar/apk/dex,也可以从SD卡中加载.
PathClassLoader 只能加载已经安装到Android系统中的apk文件。
2)插件框架如何动态加载Activity。
由于Activity需要在清单文件注册了才能使用,要么注册一个Activity基类,供插件中的Activity继承,在这个基类里做动态加载的核心逻辑,这就要求插件必须依赖某种API类库。
要么就是依赖倒转,不让插件依赖框架API,而是反过来,自动生成一个Activity类依赖(继承)插件中的Activity,这个自动生成的类就叫PluginActivity
并且声明在框架的清单文件中,如下:
原理1:Activity的启动都通过Instrumentation进行一步代理,重写Instrumentation可以得到Activity生命周期。重写 newActivity 方法构造自己的Activity对象返回给系统,这样以后onCreate等事件都入自动传入我们的Activity。也就是
在主程序的manifest中声明一个PluginActivity,当启动插件中activity A 时我们在Instrumentation的execStartActivity方法中告诉系统我要启动PluginActivity,但是当系统真正构造PluginActivity对象时我们在newActivity方法中 new A()对象返回系统。
插件开发实践:
1 关于服务
这里所说的服务是指插件项目或者主项目提供的某种功能,这种功能的调用和实现一般是跨项目的存在的。
插件和主项目之间的服务采用接口依赖的方式。
跨项目调用服务,该服务必须在插件框架中注册。
原则是:谁提供服务,谁注册服务,谁实现服务接口。调用服务只需要提供自己业务对应数据,并调用该接口的方法
2 关于接口
接口的设计目的是让插件和主项目之间的服务采用该接口相互依赖。同时,通过接口方法提供跨项目间传递数据的功能。
通过接口方法传递数据方式无非两种,
一种是通过方法的参数来set,一种是通过get方法的返回值。
对于依赖接口的设计,尽量保证简洁,高效,低的耦合性。
3 项目中的应用:
1 )
首先要搞清楚谁来提供服务,要明确该服务需要哪些数据,如何来调用。
然后根据该服务写对应的依赖服务接口,以及接口中定义的抽象方法。
2 )
对于服务提供方: 实现该服务接口,向框架注册该服务。
注册操作应该在插件的入口中执行。插件入口配置:Bundle-Activator=com.netease.plugin.webcontainer.MyActivator
// 注册服务
bundleContext.registerService(WebViewService.class.getName(), new WebViewServiceImpl(), null);
对于服务使用方:首先获取该服务,然后调用该服务的提供的方法。
//获取服务
mWebViewService = (WebViewService) PluginUtils .getService(WebViewService.class.getName());
注意: 在插件项目中提供的服务,主项目一般先启动,然后在使用该插件的服务之前一定要保证让插件项目启动起来,并注册了该服务。
3) 在服务接口的实现类中的方法中启动对应的activity来完成该功能。
但是如果方法中没有获取到content,
可以使用框架提供的全局的context即StartActivityService来跳转。
StartActivityService sas = (StartActivityService) PluginUtils .getService(StartActivityService.class.getName());
Intent intent = new Intent();
intent.setClassName(PLUGIN_ID, WebViewActivity.class.getName());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
sas.StartActivity(PLUGIN_ID, intent);