360 RePlugin插件化-项目接入-程序员宅基地

技术标签: 插件化  

RePlugin是一套完整的、稳定的、适合全面使用的,占坑类插件化方案,由360手机卫士的RePlugin Team研发,也是业内首个提出”全面插件化“(全面特性、全面兼容、全面使用)的方案
GitHub 官方文档


RePlugin 接入项目分为 主程序接入 和 插件接入。

Replugin-dev

图片中标识的 replugin-host-* 是主程序接入需要用到的,replugin-plugin-* 是插件接入需要用的。

主程序接入

注意:Android Support库和AndroidX冲突的问题

  • AS 3.2以上、Gradle 插件版本改为 4.6及以上 、compileSdkVersion 版本升级到 28及以上和buildToolsVersion 版本改为 28.0.2及以上 会引入Android新的扩展库 AndroidX。
  • RePlugin 需依赖 android.support:appcompat-v7:28.*
  • 目前还不知道如何兼容,所以在引入时做了一些修改

想了解AndroidX相关问题点击这里

1.添加 RePlugin Host Gradle 依赖

项目根目录的 build.gradle(注意:不是 app/build.gradle) 中添加 replugin-host-gradle 依赖:

buildscript {
      
    dependencies {
      
        //降低gradle插件版本
        classpath 'com.android.tools.build:gradle:3.1.0'
        classpath 'com.qihoo360.replugin:replugin-host-gradle:2.3.3'
        ...
    }
}
2.添加 RePlugin Host Library 依赖

app/build.gradle 中应用 replugin-host-gradle 插件,并添加 replugin-host-lib 依赖:

android {
     
    // ATTENTION!!! Must CONFIG this to accord with Gradle's standard, and avoid some error
    defaultConfig {
     
        applicationId "com.****.host"
        ...
    }
    ...
}
// ATTENTION!!! Must be PLACED AFTER "android{}" to read the applicationId
apply plugin: 'replugin-host-gradle'
/**
 * 配置项均为可选配置,默认无需添加
 * 更多可选配置项参见replugin-host-gradle的RepluginConfig类
 * 可更改配置项参见 自动生成RePluginHostConfig.java
 */
repluginHostConfig {
     
    /**
     * 是否使用 AppCompat 库
     * 不需要个性化配置时,无需添加
     */
    useAppCompat = true
    /**
     * 背景不透明的坑的数量
     * 不需要个性化配置时,无需添加
     */
    countNotTranslucentStandard = 6
    countNotTranslucentSingleTop = 2
    countNotTranslucentSingleTask = 3
    countNotTranslucentSingleInstance = 2
}
dependencies {
     
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //不使用 androidx库
//    implementation 'androidx.appcompat:appcompat:1.1.0'
//    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
//    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//    testImplementation 'junit:junit:4.12'
//    androidTestImplementation 'androidx.test:runner:1.2.0'
//    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    //引入 android.support 库
    //noinspection GradleCompatible
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.qihoo360.replugin:replugin-host-lib:2.3.3'
    ...
}

注意

  • 必须将包名写在applicatonId,而非AndroidManifest.xml中
  • 请将apply plugin: 'replugin-host-gradle'放在 android{} 块之后,防止出现无法读取applicationId,导致生成的坑位出现异常
  • 如果您的应用需要支持AppComat,则除了在主程序中引入AppComat-v7包以外,还需要在宿主的build.gradle中添加下面的代码:
repluginHostConfig {
   useAppCompat = true
}
  • 如果您的应用需要个性化配置坑位数量,则需要在宿主的build.gradle中添加下面的代码:
repluginHostConfig {
       
    /**
    * 背景不透明的坑的数量
    */
   countNotTranslucentStandard = 6
   countNotTranslucentSingleTop = 2
   countNotTranslucentSingleTask = 3
   countNotTranslucentSingleInstance = 2
}
3.配置 Application 类

让工程的 Application 直接继承自 RePluginApplication。

public class MyApplication extends RePluginApplication {
      
}

既然声明了Application,自然还需要在AndroidManifest中配置这个Application。

<application
        android:name=".MyApplication"
        ... />

备选:“非继承式”配置Application
若您的应用对Application类继承关系的修改有限制,或想自定义RePlugin加载过程(慎用!),则可以直接调用相关方法来使用RePlugin。

public class MyApplication extends Application {
      
    @Override
    protected void attachBaseContext(Context base) {
      
        super.attachBaseContext(base);
        RePlugin.App.attachBaseContext(this);
        ....
    }
    @Override
    public void onCreate() {
      
        super.onCreate();      
        RePlugin.App.onCreate();
        ....
    }
    @Override
    public void onLowMemory() {
      
        super.onLowMemory();
        /* Not need to be called if your application's minSdkVersion > = 14 */
        RePlugin.App.onLowMemory();
        ....
    }
    @Override
    public void onTrimMemory(int level) {
      
        super.onTrimMemory(level);
        /* Not need to be called if your application's minSdkVersion > = 14 */
        RePlugin.App.onTrimMemory(level);
        ....
    }
  @Override
    public void onConfigurationChanged(Configuration config) {
      
        super.onConfigurationChanged(config);
        /* Not need to be called if your application's minSdkVersion > = 14 */
        RePlugin.App.onConfigurationChanged(config);
        ....
    }
}

针对“非继承式”的注意点

  • 所有方法必须在UI线程来“同步”调用。切勿放到工作线程,或者通过post方法来执行
  • 所有方法必须一一对应,例如 RePlugin.App.attachBaseContext 方法只在Application.attachBaseContext中调用
  • 请将RePlugin.App的调用方法,放在“仅次于super.xxx()”方法的后面

插件接入

只需两步,就能让您的App变成“RePlugin插件”:

1.添加 RePlugin Plugin Gradle 依赖

在项目根目录的 build.gradle(注意:不是 app/build.gradle) 中添加 replugin-plugin-gradle 依赖:

buildscript {
      
    dependencies {
      
        //降低gradle插件版本
        classpath 'com.android.tools.build:gradle:3.1.0'
        classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.3.3'
        ...
    }
}
2.添加 RePlugin Plugin Library 依赖

在 app/build.gradle 中应用 replugin-plugin-gradle 插件,并添加 replugin-plugin-lib 依赖:

apply plugin: 'replugin-plugin-gradle'
dependencies {
      
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //不使用 androidx库
//    implementation 'androidx.appcompat:appcompat:1.1.0'
//    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
//    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//    testImplementation 'junit:junit:4.12'
//    androidTestImplementation 'androidx.test:runner:1.2.0'
//    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    //引入 android.support 库
    //noinspection GradleCompatible
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.qihoo360.replugin:replugin-plugin-lib:2.3.3'
    ...
}
3.添加插件别名、版本号
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <!-- 别名信息需写在 activity 之前-->
        <meta-data
            android:name="com.qihoo360.plugin.name"
            android:value="plugin2" />
        <meta-data
            android:name="com.qihoo360.plugin.version.ver"
            android:value="100" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

项目运行测试

1、外置插件

外置插件是指可通过“下载”、“放入SD卡”等方式来安装并运行的插件。

A.安装外置插件

要安装一个外置插件,只需使用 RePlugin.install 方法,传递一个“APK路径”即可。

RePlugin.install("/sdcard/exam.apk");
  • 无论安装还是升级,都会将“源文件”“移动”(而非复制)到插件的安装路径(如app_p_a)上,这样可大幅度节省安装和升级时间,但显然的,“源文件”也就会消失
  • 若想改变这个行为,您可以参考RePluginConfig中的 setMoveFileWhenInstalling() 方法
  • 升级插件和此等同
B.升级外置插件

升级插件的做法和“安装”是一样的,仍可以直接调用 RePlugin.install 方法。

RePlugin.install("/sdcard/exam_new.apk");
  • 如果插件正在运行,则不会立即升级,而是“缓存”起来。直到所有“正在使用插件”的进程结束并重启后才会生效
  • 升级可能会占用“内部存储空间”(因为要释放新的APK)
  • 不支持“插件降级”,但可以“同版本覆盖”(在 RePlugin 2.1.5版本中开始支持)

安装或升级失败(返回值为Null)的原因有如下几种:

  • 是否开启了“签名校验”功能且签名不在“白名单”之中?——通常在Logcat中会出现“verifySignature: invalid cert: ”。如是,则请参考“安全与签名校验”一节,了解如何将签名加白,或关闭签名校验功能(默认为关闭)
  • 是否将replugin-host-lib升级到2.1.4及以上?——在2.1.3及之前版本,若没有填写“meta-data”,则可能导致安装失败,返回值为null。我们在 2.1.4 版本中已经修复了此问题(卫士和其它App的所有插件都填写了meta-data,所以问题没出现)
  • APK安装包是否有问题?——请将“插件APK”直接安装到设备上(而非作为插件)试试。如果在设备中安装失败,则插件安装也一定是失败的。
  • 是否没有SD卡的读写权限?——如果您的插件APK放到了SD卡上,则请务必确保主程序中拥有SD卡权限(主程序Manifest要声明,且ROM允许),否则会出现权限问题,当然,放入应用的files目录则不受影响。
  • 设备内部存储空间是否不足?——通常出现此问题时其Logcat会出现“copyOrMoveApk: Copy/Move Failed”的警告。如是,则需要告知用户去清理手机。
C.卸载外置插件

要卸载插件,则需要使用 RePlugin.uninstall 方法。只需传递一个“插件名”即可。

RePlugin.uninstall("exam");
  • 如果插件正在运行,则不会立即卸载插件,而是将卸载诉求记录下来。直到所有“正在使用插件”的进程结束并重启后才会生效
  • 由于内置插件是捆在主程序包内的,故无法卸载“内置插件”
2、内置插件

内置插件是指可以“随着主程序发版”而下发的插件,通常这个插件会放到主程序的Assets目录下。

A.添加内置插件

添加一个内置插件是非常简单的,甚至可以“无需任何Java代码”。只需两步即可:

  • 将APK改名为:[插件名].jar
  • 放入主程序的assets/plugins目录这样,当编译主程序时,我们的“动态编译方案”会自动在assets目录下生成一个名叫“plugins-builtin.json”文件,记录了其内置插件的主要信息,方便运行时直接获取。

必须改成“[插件名].jar”后,才能被RePlugin-Host-Gradle识别,进而成为“内置插件”。

插件assets目录

B.升级内置插件

内置插件的升级分为两种情况:主程序随包升级、通过install方法升级

  • 主程序随包升级:当用户升级了带“新版本内置插件”的主程序时,则RePlugin会在使用插件前先做升级
  • 通过install方法升级:若通过 RePlugin.install 方法做的升级(大多为用户从服务器上下载并更新),则RePlugin在调用install方法时开始做升级。当然,其规则仍遵循安装插件的规则,例如“插件运行时先不覆盖”等。值得注意的是,无论采用何种方式,均“不支持降级”,但支持“同版本覆盖”升级
C.删除内置插件

删除内置插件非常简单,直接移除相应的Jar文件,其余均交给RePlugin来自动化完成。

注意:若用户已使用了内置插件,则即便用户升级主程序,其包内已不带这个内置插件,但用户仍可继续使用它。这样可防止出现“用户升级主程序后,发现内置插件突然用不了”的情况。

D.使用内置插件的时机

不同于“外置插件”需要先调用 RePlugin.install 方法后才能使用,内置插件可无需调用此方法。而一旦插件被使用,则RePlugin会在触发相应逻辑前,为您做下列操作:

  • 将内置插件释放到数据目录下(近似于调用install方法)
  • 若需要加载Dex,则还会释放“优化后的Dex”到数据目录下,这可能会需要一些时间这样做的好处是,不会占用太多的“内部存储空间”,毕竟不是所有内置插件,都一定会被用到。
3.插件预加载的用法

预加载插件就是将插件的dex“提前做释放”,并将Dex缓存到内存中,这样在下次启动插件时,可无需走dex2oat过程,速度会快很多。

  • 预加载当前安装的插件此为绝大多数用到的场景。直接预加载当前安装的插件即可,如果当前正在运行这个插件,则调用此方法则是无效的,毕竟当前插件已经早就被使用过了。
RePlugin.preload(pluginName);
  • 预加载新安装的插件此场景主要用于“后台升级某个插件”。如果此插件“正在被使用”,则必须借助 RePlugin.install 方法的返回值(新插件的信息)来做预加载。
PluginInfo pi = RePlugin.install("/sdcard/exam_new.apk");
if (pi != null) {
      
    RePlugin.preload(pi);
}
4.使用插件

通过插件名和类名调起

//第一个参数是插件的包名,第二个参数是插件的Activity。
Intent intent = RePlugin.createIntent(pluginName, className);
if (!RePlugin.startActivity(MainActivity.this, intent)) {
     
      Toast.makeText(getBaseContext(), "启动失败", Toast.LENGTH_LONG).show();
}
<

基本的接入流程就这些,如果有错误的地方,欢迎指正!

宿主与插件通信请看这里

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zuo_er_lyf/article/details/107952312

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search