我正在参与「启航计划」;略微大一点项目中插件化很常见,插件化的开源库也有几家;对比了常见的几家插件化计划后选择了腾讯的插件化计划shadow,但文档较少,一部分还靠社区维护,所以记录下我在用shadow进程中的一些整理。

零、结构

项目结构中主要有宿主,也就是咱们平常的app,它依靠introduce-shadow-lib完结对sample-manager的办理,宿主传入需求跳转的插件sample-plugin的参数,让sample-manager完结对插件的办理和调用。插件sample-plugin靠sample-runtime和sample-loader的支撑完结加载运转时所需求的环境。sample-host、sample-manager、sample-plugin虽然有依次调用,但并没有依靠联系。

Shadow的接入记录

一、插件装备

插件需求依靠runtime和loader两个模块,所以需求装备这两个模块。咱们最需求更改是partKey,apkName,apkName和版本办理的三个参数。关于loader和runtime的包名和别号都能够视情况更改。

shadow {
    packagePlugin {
        pluginTypes {
            debug {
                loaderApkConfig = new Tuple2('sample-loader-debug.apk', ':sample-loader:assembleDebug')
                runtimeApkConfig = new Tuple2('sample-runtime-debug.apk', ':sample-runtime:assembleDebug')
                pluginApks {
                    pluginApk1 {
                        businessName = 'sample-plugin'//businessName相同的插件,context获取的Dir是相同的。businessName留空,表明和宿主相同业务,直接使用宿主的Dir。
                        partKey = 'sample-plugin'//留意此处的partKey后续会用到
                        buildTask = 'assemblePluginDebug'
                        apkName = 'Vlog-plugin-debug.apk'
                        apkName = 'Vlog/build/outputs/apk/plugin/debug/Vlog-plugin-debug.apk'
                    }
                }
            }
            release {
                loaderApkConfig = new Tuple2('sample-loader-release.apk', ':sample-loader:assembleRelease')
                runtimeApkConfig = new Tuple2('sample-runtime-release.apk', ':sample-runtime:assembleRelease')
                pluginApks {
                    pluginApk1 {
                        businessName = 'demo'
                        partKey = 'sample-plugin'
                        buildTask = 'assemblePluginRelease'
                        apkName = 'plugin-app-plugin-release.apk'
                        apkPath = 'plugin-app/build/outputs/apk/plugin/release/plugin-app-plugin-release.apk'
                    }
                }
            }
        }
        loaderApkProjectPath = 'sample-loader'
        runtimeApkProjectPath = 'sample-runtime'
        //插件版本办理
        version = 4
        compactVersion = [1, 2, 3]
        uuidNickName = "1.1.5"
    }
}

咱们能够集成多个pluginApk来更新多个插件,集成方法和在pluginApks层级下面的pluginApk1方法共同,咱们能够新增pluginApk2,pluginApk3等等。插件自身最开始的applicationId能够不用管它,咱们新的装备需和宿主同applicationid,和咱们的defaultConfig是同级的。不然会报错插件和宿主包名不共同。

// 将插件applicationId设置为和宿主相同
productFlavors {
    plugin {
        applicationId "com.tencent.shadow.sample.host"
    }
}

假如有多个插件,咱们需求确保我的partKey仅有,uuidNickName最好也坚持仅有,不论多少个插件,每个插件的applicationId都要和宿主共同。

二、个人完结

2.1、introduce-shadow-lib

该模块是对插件办理模块的进行办理的模块,依靠于宿主。在这个项目中咱们需求给到manager-project编译好的apk途径。在shadow的示例中是在本地编译然后adb推送到手机上,指定固定的途径。但咱们的完结肯定不能如此,咱们需求从远端下载保存到本地,动态的设置manager-project apk的途径。下载同时需求考虑网络无法下载,下载中止,判别是否已下载,是否需求更新等作业。

2.2、manager-project

插件办理需求做的是对插件的下载、验证、更新、解析、安装等作业。shadow自身没有完结对插件的下载、验证、更新作业,咱们需求完结咱们自己的插件办理作业。目前按adb push的方法直接放在手机下,后续更改未下载方法。

2.3、宿主传参

这些参数本来是写死在manager-project里面的,但咱们的业务愈加的灵活,写死肯定是不可,咱们需求动态的传入这些参数来完结动态插件化。

参数键 参数值 阐明
KEY_PLUGIN_ZIP_PATH /data/local/tmp/plugin-debug.zip 插件的本地地址,插件需求先下载下来,能够提前异步下载也能够比及调用时再下载
KEY_PLUGIN_PART_KEY sample-plugin 插件的键名,在插件模块的build gradle里有装备,需相同
KEY_ACTIVITY_CLASSNAME com.jiayz.videorecorder.MainActivity 需求发动的插件的包名加activity类名

2.4、SDK的自发布

在前面的几个模块有很多的依靠腾讯的SDK,它们现已被发布到了maven。但是shadow不推荐咱们在出产环境中使用他们现已发布的库,推荐咱们自己编译发布SDK更改依靠地址

Shadow的接入记录

三、包名的更改

咱们假如想移植到自己的项目中去,最好仍是把包名改一下,不然顶这个tencent.shadow.samplexxx也欠好,但是在改包名的进程中有一些需求留意的当地,不然会导致项目运转出错。

3.1、不能动的包和类名

shadow规则了有几个不能动的包名和类名,他在他的sdk现已写死包名和类名,分别是:

    1. manager-project下的com.tencent.shadow.dynamic.impl包下的两个类-ManagerFactoryImpl和WhiteList
    2. sample-loader下的com.tencent.shadow.dynamic.loader.impl.DynamicPluginLoader类

3.2、需同步的包名

咱们更改完咱们的包名后需求同步的更改咱们的包名,不然会呈现ClassNotFound的反常,需求同步的包如下:

    1. 假如咱们更改了introduce-shadow-lib模块下的MainPluginProcessService的包名,咱们需求同步manager-project模块下的原先SamplePluginManager类中的getPluginProcessServiceName方法返回的包名,确保和修改的共同。
    2. 假如咱们更改了sample-runtime原先的包名com.tencent.shadow.sample.runtime,那么相应的咱们需求同步introduce-shadow-lib模块下Manifest注册的活动,不然会提示不能发动活动,是否已在Manifest下注册该活动。

Shadow的接入记录

四、插件的编译发布

先编译整个项目,确保runtime和loader生成了apk,且apk途径和你在插件中装备的runtime和loaderapk途径共同,不然会报错找不到文件。

在你插件都依靠成功的情况下,能够指令行运转gradle指令

./gradlew packageDebugPlugin

但我履行指令失利了,其实也能够在AndroidStudio右侧的gradle工具栏点击履行。

Shadow的接入记录

履行完结后会在插件app的输出目录下发现plugin目录,里面有plugin.apk,再履行plugin-manager下的plugin使命的

Shadow的接入记录

履行完结后,项目根build下看到一个plugin-debug.zip文件,依据业务自己更改zip姓名。

Shadow的接入记录

此刻插件编译完结。后续咱们能够给到后台上传发布新插件,供后续的下载更新。 个人见解不尽正确,欢迎我们交流指正。

参考链接:

www.jianshu.com/p/f00dc8372…