RePlugin是一套完整的、稳定的、适合全面使用的,占坑类插件化方案。
具体来说有如下特点:
完整的:让插件运行起来“像单品那样”,支持大部分特性
稳定的:如此灵活完整的情况下,其框架崩溃率仅为业内很低的“万分之一”
适合全面使用的:其目的是让应用内的“所有功能皆为插件”
占坑类:以稳定为前提的Manifest占坑思路
插件化方案:基于Android原生API和语言来开发,充分利用原生特性
极其灵活:主程序无需升级(无需在Manifest中预埋组件),即可支持新增的四大组件,甚至全新的插件
**非常稳定:**Hook点仅有一处(ClassLoader),无任何Binder Hook!如此可做到其崩溃率仅为“万分之一”,并完美兼容市面上近乎所有的Android ROM
特性丰富:支持近乎所有在“单品”开发时的特性。包括静态Receiver、Task-Affinity坑位、自定义Theme、进程坑位、AppCompat、DataBinding等
易于集成:无论插件还是主程序,只需“数行”就能完成接入
管理成熟:拥有成熟稳定的“插件管理方案”,支持插件安装、升级、卸载、版本管理,甚至包括进程通讯、协议版本、安全校验等
数亿支撑:有360手机卫士庞大的数亿用户做支撑,三年多的残酷验证,确保App用到的方案是最稳定、最适合使用的
RePlugin 项目一共4个库,其中有两个是library库,两个是gradle插件工程,工程截图如下:
1. replugin-host-gradle
host工程使用的Gradle插件,主要功能是宿主程序打包的过程中动态的修改AndroidManifest.xml
的信息,动态的生成占位各种Activity、provider和service的声明。
2. replugin-host-library
宿主工程的library,RePlugin 的核心功能都在这个库中,RePlugin 框架的初始化,插件的安装,加载以及启动都与这个库有很大关系。
3. replugin-plugin-gradle
插件工程的Gradle的插件,替换插件工程中的Activity的继承全部替换成Replugin库中定义的XXXActivity。动态的将插件apk中调用LocalBroadcastManager的地方修改为Replugin中的PluginLocalBroadcastManager调用,动态修改ContentResolver和ContentProviderClient的调用修改成Replugin调用,动态的修改插件工程中所有调用Resource.getIdentifier方法的地方,将第三参数修改为插件工程的包名 。
4. replugin-plugin-library
插件工程的library,通过反射的方式来使用宿主程序中接口和功能。
RePlugin 对插件的管理有两种方式:内置插件和外置插件
外置插件是指可通过“下载”、“放入SD卡”等方式来安装并运行的插件。
内置插件是指可以“随着主程序发版”而下发的插件,通常这个插件会放到主程序的Assets目录下。
大多数情况使用插件都是外置的方式,所以接下来我们就以外置的方式来梳理RePlugin的集成方式。
要将 RePlugin 集成到我们自己的项目中,需要分别在宿主工程和插件工程分别集成RePlguin框架:
buildscript {
dependencies {
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.2.4'
...
}
}
apply plugin: 'replugin-host-gradle'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
implementation 'com.qihoo360.replugin:replugin-host-lib:2.2.4'
}
注意:请将apply plugin: ‘replugin-host-gradle’放在 android{} 块之后,防止出现无法读取applicationId,导致生成的坑位出现异常
public class App extends RePluginApplication {
...
}
然后在AndroidManifest中配置这个App
<application
android:name=".MainApplication"
... />
当宿主功能已经定义了Application,那此时就直接找到它的基类的,该基类必然是继承自Application,此时我们只需要让该基类继承RePluginApplication即可。
上面的方法无论怎么都是采用继承的方式来做的,如果实在不想继承,还可以在已有的Application中的相应生命周期函数中调用RePlugin的方法:
RePlugin.App.attachBaseContext(this);
RePlugin.App.onCreate();
RePlugin.App.onLowMemory();
RePlugin.App.onTrimMemory(level);
RePlugin.App.onConfigurationChanged(config);
buildscript {
dependencies {
classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.2.4'
...
}
}
apply plugin: 'replugin-plugin-gradle'
dependencies {
compile 'com.qihoo360.replugin:replugin-plugin-lib:2.2.4'
...
}
经过以上操作,宿主和插件的RePlguin框架就算集成完成了,接下来就是如何去在项目中使用了。
对于插件App经过上面的集成步骤后就可以直接打包在宿主工程中使用了,但怎么使用呢? 拿外置集成来说,我们只需要将打包好的插件APK放置在手机特定目录下,这里我们选择放在SD卡的根目录下,然后在host宿主工程中调用RePlugin 的API去安装该插件APK就行,安装成功后就可以直接启动插件了,具体做法如下:
1. 首先打包插件APK,pluginApp.apk, 将该APK放置在SD卡根目录下;
2. 在宿主工程中安装插件APK pluginApp.apk, 完整的安装过程代码如下:
private void installPlugin() {
//判断插件是否已经安装,插件的名字为插件的包名com.example.pluginapp
PluginInfo info = MP.getPlugin("com.example.pluginapp", true);
if (info == null) {
//插件apk 位于sd卡根目录下
String path = Environment.getExternalStorageDirectory().getPath() + "/pluginApp.apk";
//判断插件apk文件是否存在
File pluginApk = new File(path);
if (pluginApk.exists()) {
PluginInfo pluginInfo = RePlugin.install(path);
if (pluginInfo == null) {
Toast.makeText(this, "插件安装失败", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "插件安装成功", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "sd卡路径下无插件apk", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "插件已经安装", Toast.LENGTH_SHORT).show();
}
}
3 .如果安装成功,接下来就可以直接启动插件了,代码如下:
private void setupPlugin() {
Intent intent = RePlugin.createIntent("com.example.pluginapp", "com.example.pluginapp.MainActivity");
RePlugin.startActivity(MainActivity.this, intent);
}
其实创建Intent的操作可以不使用RePlugin提供的接口,用Android 原生的方式也是可以的。