RePlugin已经开放有一段时间了,但是一直没空搞这东西,这几天有机会来学习一下,并且打算使用到公司项目中去,刚刚集成完毕,打算和大家分享一下集成过程。
RePlugin是360新开发的插件化库,听说集成简单、效率高、稳定性强,最主要的是安装插件之后不需要重启,至于前几个特点,我也不知道怎么说,用用看吧。RePlugin、中文官网这个官网不是官方注册的,但是得到了官方的认可。
先看一下效果:
RePlugin分为内置和外置集成,这里就只介绍外置集成。
一、配置项目目录下的gradle:
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.1.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
注意mavenLocal()必须放在jcenter()之前。
二、配置app目录下的gradle:
apply plugin: 'com.android.application'
apply plugin: 'replugin-host-gradle'
// If use AppCompat, open the useAppCompat
repluginHostConfig {
useAppCompat = true
}
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.morse.testapp"
minSdkVersion 20
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'com.umeng.analytics:analytics:latest.integration'
compile 'org.xutils:xutils:3.5.0'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.qihoo360.replugin:replugin-host-lib:2.1.5'
compile 'org.xutils:xutils:3.5.0'
}
这里引入xtuils是为了下载插件。
三、配置Application,这里采用继承式,继承RePluginApplication:
package com.morse.testapp;
import com.qihoo360.replugin.RePlugin;
import com.qihoo360.replugin.RePluginApplication;
import com.qihoo360.replugin.RePluginCallbacks;
import com.qihoo360.replugin.RePluginConfig;
import org.xutils.x;
/**
* @Author:曾明
* @Time:2017/5/19 18:26
* @Description:
*/
public class TestApplication extends RePluginApplication {
private static TestApplication mInstance;
@Override
public void onCreate() {
super.onCreate();
// CrashHandler crashHandler = CrashHandler.getInstance();
// crashHandler.init(getApplicationContext());
mInstance = this;
x.Ext.init(this);
x.Ext.setDebug(BuildConfig.DEBUG); // 开启debug会影响性能
RePlugin.App.onCreate();
}
public static TestApplication getAppContext() {
return mInstance;
}
@Override
protected RePluginConfig createConfig() {
RePluginConfig c = new RePluginConfig();
// 允许“插件使用宿主类”。默认为“关闭”
c.setUseHostClassIfNotFound(true);
// FIXME RePlugin默认会对安装的外置插件进行签名校验,这里先关掉,避免调试时出现签名错误
c.setVerifySign(false);
c.setPrintDetailLog(BuildConfig.DEBUG);
c.setUseHostClassIfNotFound(true);
// 针对“安装失败”等情况来做进一步的事件处理
c.setEventCallbacks(new HostEventCallbacks(this));
c.setMoveFileWhenInstalling(true);
// FIXME 若宿主为Release,则此处应加上您认为"合法"的插件的签名,例如,可以写上"宿主"自己的。
// RePlugin.addCertSignature("AAAAAAAAA");
return c;
}
@Override
protected RePluginCallbacks createCallbacks() {
return new HostCallbacks(this);
}
}
HostEventCallbacks和HostCallbacks是自定义的,分别集成RePluginEventCallbacks和RePluginCallbacks。RePluginCallbacks这个回调可以监测到本地有没有下载插件apk,并且可以做一下自定义的行为:
package com.morse.testapp;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import com.qihoo360.replugin.RePlugin;
import com.qihoo360.replugin.RePluginCallbacks;
import com.qihoo360.replugin.model.PluginInfo;
import org.xutils.common.Callback;
import org.xutils.http.RequestParams;
import org.xutils.x;
import java.io.File;
/**
* 宿主针对RePlugin的自定义行为
*
* @Author:曾明
* @Time:2017/7/15 17:32
* @Description:
*/
public class HostCallbacks extends RePluginCallbacks {
public HostCallbacks(Context context) {
super(context);
}
@Override
public boolean onLoadLargePluginForActivity(Context context, String plugin, Intent intent, int process) {
return super.onLoadLargePluginForActivity(context, plugin, intent, process);
}
@Override
public boolean onPluginNotExistsForActivity(final Context context, final String plugin, Intent intent, int process) {
// FIXME 当插件"没有安装"时触发此逻辑,可打开您的"下载对话框"并开始下载。
// FIXME 其中"intent"需传递到"对话框"内,这样可在下载完成后,打开这个插件的Activity
if (BuildConfig.DEBUG) {
Log.d("morse", "onPluginNotExistsForActivity: Start download... p=" + plugin + "; i=" + intent);
}
return super.onPluginNotExistsForActivity(context, plugin, intent, process);
}
}
RePluginEventCallbacks是安装插件apk是使用的回调,能够监测到插件apk的安装情况:
package com.morse.testapp;
import android.content.Context;
import android.util.Log;
import com.qihoo360.replugin.RePluginEventCallbacks;
import com.qihoo360.replugin.model.PluginInfo;
/**
* @Author:曾明
* @Time:2017/7/15 17:33
* @Description:
*/
public class HostEventCallbacks extends RePluginEventCallbacks {
public HostEventCallbacks(Context context) {
super(context);
}
@Override
public void onInstallPluginSucceed(PluginInfo info) {
Log.d("morse", "onInstallPluginSucceed: Failed! info=" + info);
super.onInstallPluginSucceed(info);
}
@Override
public void onInstallPluginFailed(String path, InstallResult code) {
// FIXME 当插件安装失败时触发此逻辑。您可以在此处做“打点统计”,也可以针对安装失败情况做“特殊处理”
// 大部分可以通过RePlugin.install的返回值来判断是否成功
Log.d("morse", "onInstallPluginFailed: Failed! path=" + path + "; r=" + code);
super.onInstallPluginFailed(path, code);
}
@Override
public void onStartActivityCompleted(String plugin, String activity, boolean result) {
// FIXME 当打开Activity成功时触发此逻辑,可在这里做一些APM、打点统计等相关工作
Log.d("morse", "onStartActivityCompleted: plugin=" + plugin + "\r\n result=" + result);
super.onStartActivityCompleted(plugin, activity, result);
}
}
四、启动插件,在启动插件的时候,有几个地方需要注意一下:
1、需要检测插件是否安装;
2、如果没有安装,检测本地是否下载插件;
3、没有下载插件,需要先下载插件;
4、如果没有安装插件,需要安装插件;
5、启动插件;
//检测插件是否安装
PluginInfo info = MP.getPlugin("androidhelper", true);
//未安装插件
if (null == info) {
//检测插件是否下载
File file = new File("/sdcard/dht", "androidhelper.apk");
if (!file.exists()) {
//下载插件
Toast.makeText(MainActivity.this, "插件不存在", Toast.LENGTH_SHORT).show();
} else {
//安装插件
PluginInfo in = RePlugin.install("/sdcard/dht/androidhelper.apk");
if (null == in) {
Toast.makeText(MainActivity.this, "安装插件失败", Toast.LENGTH_SHORT).show();
}
}
return;
}
//启动插件
RePlugin.startActivity(MainActivity.this, RePlugin.createIntent("androidhelper", "com.morse.replugin.MainActivity"));
到这里,宿主集成就完成了。
插件apk的集成也差不多:
一、项目目录下的gradle配置:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.1.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
二、app目录下的gradle配置:
apply plugin: 'com.android.application'
apply plugin: 'replugin-plugin-gradle'
android {
compileSdkVersion 26
buildToolsVersion "26.0.0"
defaultConfig {
applicationId "com.morse.replugin"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'com.qihoo360.replugin:replugin-plugin-lib:2.1.5'
}
三、这一步与宿主的配置不一样,宿主不需要配置清单文件,插件需要:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.morse.replugin">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:exported="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
intent-filter>
activity>
<meta-data
android:name="com.qihoo360.plugin.name"
android:value="androidhelper" />
<meta-data
android:name="com.qihoo360.plugin.version.ver"
android:value="100" />
application>
manifest>
注意meta,name是固定的,只需要修改value就ok,还有,activity必须暴露,否则无法访问到。
好了,RePlugin的集成到这里就完成了,赶紧去试试吧。
传送门
RePlugin使用的时候,可能在控制台会打印出一下日志:
这个日志并不说明安装插件失败了,看到下面PInfo的信息就表示已经集成RePlugin成功了。
本文提供RePlugin1.X版本的集成方案,如果博友使用的是最新的RePlugin库,请移步:RePlugin 2.X使用教程