一、准备工作
下载原项目
shadow地址
Android studio版本保持版本最新
gradle版本7.0.2及以上
JDK版本:最低要求11
二、导入原Shadow工程下的moudle
1:introduce-shadow-lib
该moudle是用于做APP开始时的初始化用的,详见InitApplication类,moudle位置projects->sample->maven->host-project->introduce-shadow-lib
2:sample-host-lib
moudle位置projects->sample->source->sample-host-lib
三:配置gradle
1、project的gradle增加shadow版本信息
ext{
shadow_version ='2.2.1'
}
2、setting.gradle中导入项目,并增加shadow支持
3、app下的build.gradle配置
implementation"com.tencent.shadow.dynamic:host:$shadow_version"
implementation project(‘:introduce-shadow-lib’)
implementation project(‘:sample-host-lib’)
四、 导入插件管理项目
moudle位置projects->sample->source->sample-manager
五、项目配置
1、项目初始化
项目入口下 调用InitApplication.onApplicationCreate(this);初始化
2、打包插件apk
使用命令,或者在Gradle 工具窗口点击 assembleDebug:
./gradlew assembleDebug
生成apk路径:
sample-manager/build/outputs/apk/debug/sample-manager-debug.apk
至此,插件管理工程完成。
3、在宿主app下创建assets目录,将sample-manager-debug.apk拷进目录中
六、插件集成
1、引入plugin所需moudle
2、将projects->sample->source->sample-plugin 目录下sample-loader和sample-runtime 两个moudle引入项目中,并进行依赖
3、项目build.gradle 增加ext.shadow_version =‘2.2.1’ 版本声明
4、项目build.gradle 增加maven
maven{
name ="GitHubPackages"
url"https://maven.pkg.github.com/tencent/shadow"
//一个只读账号兼容Github Packages暂时不支持匿名下载
//https://github.community/t/download-from-github-package-registry-without-authentication/14407
credentials{
username ='readonlypat'
password ='\u0067hp_s3VOOZnLf1bTyvHWblPfaessrVYyEU4JdNbs'
}
}
5、app下的build.gradle 配置
新增依赖
implementation “com.tencent.shadow.core:activity-container:$shadow_version”
在gradle配置插件
app下的build.gradle中新增
//这段buildscript配置的dependencies是为了apply plugin: 'com.tencent.shadow.plugin'能找到实现
buildscript {
repositories {
if (!System.getenv().containsKey("DISABLE_TENCENT_MAVEN_MIRROR")) {
maven { url 'https://mirrors.tencent.com/nexus/repository/maven-public/' }
} else {
google()
mavenCentral()
}
maven {
name = "GitHubPackages"
url "https://maven.pkg.github.com/tencent/shadow"
//一个只读账号兼容Github Packages暂时不支持匿名下载
//https://github.community/t/download-from-github-package-registry-without-authentication/14407
credentials {
username = 'readonlypat'
password = '\u0067hp_s3VOOZnLf1bTyvHWblPfaessrVYyEU4JdNbs'
}
}
mavenLocal()
}
dependencies {
classpath "com.tencent.shadow.core:gradle-plugin:$shadow_version"
}
}
在最底下配置 my-load 和 my-runtime 模块生成的 apk 路径及名字要对应,可以先build 生成一个 apk 查看路径和名字, 插件apk路径名字也一样,可以先build生成,再配置路径
apply plugin: 'com.tencent.shadow.plugin'
shadow {
packagePlugin {
pluginTypes {
debug {
loaderApkConfig = new Tuple2('my-loader-debug.apk', ':my-loader:assembleDebug')
runtimeApkConfig = new Tuple2('my-runtime-debug.apk', ':my-runtime:assembleDebug')
pluginApks {
pluginApk1 {
businessName = 'my-plugin'//businessName相同的插件,context获取的Dir是相同的。businessName留空,表示和宿主相同业务,直接使用宿主的Dir。
partKey = 'my-plugin'
buildTask = 'assembleDebug'
apkName = 'app-debug.apk'
apkPath = 'app/build/outputs/apk/debug/app-debug.apk'
// hostWhiteList = ["com.tencent.shadow.sample.host.lib"] // 配置允许插件访问宿主的类
}
}
}
release {
loaderApkConfig = new Tuple2('my-loader-release-unsigned.apk', ':my-loader:assembleRelease')
runtimeApkConfig = new Tuple2('my-runtime-release-unsigned.apk', ':my-runtime:assembleRelease')
pluginApks {
pluginApk1 {
businessName = 'demo'
partKey = 'my-plugin'
buildTask = 'assembleRelease'
apkName = 'app-release-unsigned.apk'
apkPath = 'app/build/outputs/apk/release/app-release-unsigned.apk'
// hostWhiteList = ["com.tencent.shadow.sample.host.lib"] // 配置允许插件访问宿主的类
}
}
}
}
loaderApkProjectPath = 'my-loader'
runtimeApkProjectPath = 'my-runtime'
version = 4
compactVersion = [1, 2, 3]
uuidNickName = "1.1.5"
}
}
android 标签下配置
// 将插件applicationId设置为和宿主相同
productFlavors {
plugin {
applicationId "com.ylyd.sha"
}
}
6、编译
使用命令,或者在Gradle 工具窗口点击 packageDebugPlugin:
./gradlew packageDebugPlugin
生成zip路径:
项目project->build->plugin-debug.zip
将该插件包拷贝到宿主的assets目录下
七 宿主加载插件并启动
一:拷贝插件到sd卡
将assets下的插件管理类 拷贝进sd卡
String APK_NAME_DEBUG = "sample-manager-debug.apk";
try {
File file1 =new File(this.getFilesDir().getAbsolutePath() + File.separator + "plugin-debug.zip");
InputStream open1 = null;
open1 = this .getAssets() .open("plugin-debug.zip");
FileUtil.copyFile(open1, file1, true);
File file =new File(this.getFilesDir().getAbsolutePath() + File.separator + APK_NAME_DEBUG);
InputStream open = null;
open = this .getAssets() .open(APK_NAME_DEBUG);
FileUtil.copyFile(open, file, true);
startPluginActivity();
} catch (IOException e) {
throw new RuntimeException(e);
}
流程执行完毕好调用插件管理的代码,加载插件即可
PluginManager pluginManager = InitApplication.getPluginManager();
Bundle bundle = new Bundle();
//插件 zip地址,这几个参数也都可以不传,直接在 PluginManager 中硬编码
///data/local/tmp/plugin-debug.zip
bundle.putString("pluginZipPath", this.getFilesDir().getAbsolutePath() + File.separator +"plugin-debug.zip");
//partKey 每个插件都有自己的 partKey 用来区分多个插件,如何配置在下面讲到
bundle.putString("KEY_PLUGIN_PART_KEY", "my-plugin");
// 路径举例:com.google.samples.apps.sunflower.GardenActivity
bundle.putString("KEY_ACTIVITY_CLASSNAME", "com.tencent.shadow.sample.plugin.MainActivity"
);
// 要传入到插件里的参数
bundle.putBundle("extra_to_plugin_bundle", new Bundle());
pluginManager.enter(MainActivity.this, FROM_ID_START_ACTIVITY, bundle, new EnterCallback() {
@Override
public void onShowLoadingView(View view) {
MainActivity.this.setContentView(view);//显示Manager传来的Loading页面
}
@Override
public void onCloseLoadingView() {
}
@Override
public void onEnterComplete() {
}
});