什么是插件化?插件化开发是将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk。插件apk是不需要安装的,运行在手机上的是宿主apk,当需要插件内容的时候,就需要通过宿主apk先加载插件,然后才能操作插件,也就是说插件是没有独立运行环境的,必须依赖宿主的环境。
学习插件化,需要了解宿主、插件和标准的关系
- 宿主:运行在手机上的apk
- 插件:服务器上下载的apk包,没有经过安装
- 标准:指插件应该遵循宿主提供的接口协议
下面就以启动插件activity为例,开始撸代码环节
一、创建宿主标准
创建library库,另外这些标准一般都是宿主中的方法,比如生命周期方法等,另外需要将宿主的上下文环境传递给插件activity,所以定义接口PluginActivityInterface,代码如下:
二、创建宿主插件包
记住一点插件是一个apk,所以创建的应该是module。
1、BaseActivity
创建基类,实现了宿主的接口标准,并拿到宿主的上下文环境
2、MainActivity
在插件中创建一个启动的activity,命名MainActivity,继承BaseActivity。并在相对应的xml布局中添加了几个按钮
这里的findViewById不能是系统的,而应该是宿主的,因为插件是没有上下文环境的,使用默认系统的会抛出异常。所以这里会调用父类BaseActivity的该方法,父类BaseActivity的这部分代码如下:
最终会调用宿主mActivity的该方法,startActivity也是同样的道理。这里的mActivity其实就是代理Activity。
三、创建代理activity
为什么要创建代理activity?我们都知道activity的跳转就是一个压栈的过程,创建代理activity其实就是为插件activity模拟这一过程,这样当我们点击返回键的时候才能从插件回到宿主activity中。代码如下:
/**
* <pre>
* author : QB
* time : 2019/8/6
* version : v1.0.0
* desc : 必须继承 Activity 继承AppcompatActivity会出错
* </pre>
*/
public class ProxyActivity extends Activity {
@Override
public Resources getResources() {
return PluginManager.getInstance(this).getPluginResource();
}
@Override
public ClassLoader getClassLoader() {
return PluginManager.getInstance(this).getClassLoader();
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//通过classLoader加载插件的class文件
String className = getIntent().getStringExtra("className");
Log.e("类名-----", className);
try {
//加载插件activity类信息
Class<?> aClass = getClassLoader().loadClass(className);
Constructor<?> constructor = aClass.getConstructor();
Object obj = constructor.newInstance();
//实例化插件activity类
PluginActivityInterface pluginInterface = (PluginActivityInterface) obj;
//初始化插件上下文
pluginInterface.initApp(this);
Bundle bundle = new Bundle();
bundle.putString("className", "宿主跳转到插件");
//执行插件activity的onCreate()方法
pluginInterface.onCreate(bundle);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将插件中启动页面压入栈中
*/
public void startActivity(Intent intent) {
String className = intent.getStringExtra("className");
Intent intentNew = new Intent(this, ProxyActivity.class);
intentNew.putExtra("className", className);
super.startActivity(intentNew);
}
}
上面重写了两个方法getClassLoader()和getResources()。这两个方法返回的是对应插件app的类加载器和资源,,只有拿到类加载器才能通过反射拿到要操作的插件activity对象;只有拿到资源信息才能够加载layout布局(否则之前调用mActivity.findViewById()会找不到我们的控件)。下面就看一下插件的安装过程,就是将这两个东东进行初始化。
四、安装插件
插件apk,打包成功后,放在data/sdcard目录下,获取插件apk的路径
1、获取插件包的类加载器
2、获取插件包的资源
3、提供方法供外部调用
五、跳转到插件activity
这里我们需要拿到插件apk中清单文件注册的第一个activity,也就是启动activity。
这样就拿到了插件activity的类名。跳转到代理activity的时候将类名称信息保存到intent中携带过去,这样才能通过插件的classLoader将类加载出来。
最后别忘记加访问sdcard权限哦!!!!
总结:
1:插件中为什么不能使用this
答:因为插件是没有安装手机上安装的,是无法拥有组件环境的
2:插件中为什么要是用代理的activity
答:由于插件中的Activity,并不是一个能够运行的组件,所以需要代理的Activity去代替 插件中的Activity (例如:Activity任务进栈)。
下一节将讲述如何去处理插件中静态广播的注册?