上文讲到了插件的简单改造,当然只是简单地把插件运行起来而已,可以查看:
https://blog.csdn.net/weixin_39513118/article/details/84777809
这一次来简单学习一下插件化中的宿主的改造。
由于在app开发的初始阶段并没有考虑到插件化,所以一开始是完全没有基础的。随着app的开发,集成的功能越来越多,分模块就变得越来越急迫。
废话不多说,直接开始了。
0. 降低当前gradle的版本:
classpath 'com.android.tools.build:gradle:3.1.4'
将原来的3.2.1降低到3.1.4,未来可能逐步提高gradle的版本,因为插件化框架不太支持较高版本的gradle。
1. 在项目的build文件中添加插件:
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
添加了下面一行:
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.3.1'
2. 在app/build的android{}后面添加:
apply plugin: 'replugin-host-gradle'
在后面添加是为了可以正确读取插件配置。
3. (可选)支持AppCompat包:
repluginHostConfig {
useAppCompat = true
}
更具官方文档,这个在不需要使用的使用可以不添加,具体这个包是干什么的,读者可以自行查阅。
4. 在app/build中引入插件相关的文件:
implementation 'com.qihoo360.replugin:replugin-host-lib:2.3.1'
5. 继承项目的Application,并在里面初始化插件所需要的环境变量:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
RePlugin.App.attachBaseContext(this);
}
注意: RePlugin.App.attachBaseContext(this);一定要放在最前面
@Override
public void onCreate() {
super.onCreate();
RePlugin.App.onCreate();
context = getApplicationContext();
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(context);
}
在onCreat()方法中也要添加
注意:
- 被忘了在AndroidManifest中添加继承的Application。
- 宿主在编译的时候会明显慢于未引入插件版本。
- 如果遇到如下问题:
java.lang.RuntimeException: Unable to get provider com.xq.enterprisesecurityexperts.loader.p.ProviderN1: java.lang.ClassNotFoundException:
请检查Application的
RePlugin.App.attachBaseContext(this);
和
RePlugin.App.onCreate();
是否添加正确了。
6. 在界面里添加三个按钮,分别表示插件的安装,启动和卸载:
7. 安装插件:
private void initData(String pluginName) {
Log.e(TAG, "initData: 安装插件1");
if (!RePlugin.isPluginInstalled(pluginName)){
String pluginApk = pluginName + ".apk";//注释(1)
String fileName = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + pluginApk;//注释(2)
Log.e(TAG, "initData: " + fileName);
File pluginFile = new File(fileName);
Log.e(TAG, "initData: 安装插件2");
//文件不存在就返回
if (!pluginFile.exists()){ //注释(3)
Log.e(TAG, "initData: 安装插件3");
Toast.makeText(MyApplication.getContext(), "安装包不存在!", Toast.LENGTH_SHORT).show();
return;
}
Log.e(TAG, "initData: 安装插件4");
PluginInfo info = null;
if (pluginFile.exists()) {
Log.e(TAG, "initData: 安装插件5");
Toast.makeText(MyApplication.getContext(), "安装 patrol_plugin 成功 " + pluginName, Toast.LENGTH_SHORT).show();
info = RePlugin.install(fileName);
}
Log.e(TAG, "initData: 安装插件6");
if (info != null){
Log.e(TAG, "initData: 安装插件7");
//预先加载
RePlugin.preload(info); //注释(4)
Toast.makeText(MyApplication.getContext(), "预加载 patrol_plugin 成功 " + pluginName + info.getName(), Toast.LENGTH_SHORT).show();
}
Log.e(TAG, "initData: 安装插件8");
}
Log.e(TAG, "initData: 安装插件9");
}
解释:
- 首先传入插件的apk的名称,宿主会根据插件名进行安装
- 传入插件的存放位置(后期可以改为插件的下载位置),这里设置为sd卡的更目录。
- 下面的代码表示:先检查安装包是否存在,存在则进行安装。Info表示插件的安装信息,类似apk的安装信息。如果安装成功,这个变量不会为null。
- 插件安装成功以后,最好对插件进行预加载,这样可以加快插件的启动速度。我测试了一下,经过预加载的插件和原生的模块在宿主中的启动速度相差无几,体验上几乎没有差别。
8. 启动插件:
if (RePlugin.isPluginInstalled("patrol_plugin")) { //注释(1)
Log.e(TAG, "onViewClicked: 开始插件");
Intent intent17 = new Intent(); //注释(2)
intent17.putExtra("personId", personId);
Log.e(TAG, "onViewClicked: 开始插件 " + pse);
intent17.setComponent(new ComponentName("com.xq.enterprisesecurityexperts.plugins.patrolpluginapplication", "com.xq.enterprisesecurityexperts.plugins.patrolpluginapplication.MainActivity"));//注释(3)
RePlugin.startActivity(getActivity(), intent17);
} else {
Toast.makeText(getContext(), "插件未安装!", Toast.LENGTH_SHORT).show();
}
- 启动插件的时候先判断插件是否被安装
- 可以利用intent对插件传递参数
- 启动时需要传递两个字符串,前面一个是插件的applicationId,后面一个是插件的Activity。官方文档说是前一个参数可以是插件的别名,但是需要在其他地方声明这个别名,但是效果是一样的,可能别名的方式更加简洁一点,但是我运行失败了。
9. 卸载插件:
Log.e(TAG, "onViewClicked: 卸载1");
if (RePlugin.isPluginInstalled("patrol_plugin")) { //注释(1)
Log.e(TAG, "onViewClicked: 卸载2");
Toast.makeText(getActivity(), "卸载插件,APP重启以后生效!",Toast.LENGTH_SHORT).show();
RePlugin.uninstall("com.xq.enterprisesecurityexperts.plugins.patrolpluginapplication"); //注释(2)
}
- 卸载时先要判断插件是否被安装
- 卸载时的参数为插件的applicationId,也可以的别名。
注意:
- 插件在安装成功以后apk包会被删除,下次重新安装的时候需要重新导入。
- 插件卸载的时候不会马上生效,即点击“卸载”以后,还是可以打开插件,需要退出app,下次打开的才会成功卸载,如果还是可以打开插件,请再次重新突退出并打开app。