• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

接入腾讯Shadow插件化框架

武飞扬头像
Rookie_
帮助1

一.源码地址

github.com/Tencent/Sha…

文档:

github.com/Tencent/Sha…

github.com/Tencent/Sha…

github.com/Tencent/Sha…

其实官方文档说的已经很清楚了,建议反复阅读官方文档,才能对后面的接入有更好的理解.

二.体验demo

学新通

三.接入到项目

3.1首先将插件库发布的本地仓库中,方便后续依赖

在`buildScripts/gradle/maven.gradle`文件中配置了Shadow的Maven发布脚本。
正式使用时,请修改其中的两个GroupID变量:`coreGroupId`、`dynamicGroupId`,
以及`setScm`方法中的两个URL到自己的版本库地址上。

然后将`mavenLocal()`改为自己发布的目标Maven仓库。

执行`./gradlew publish`即可将Shadow SDK发布到Maven仓库。

官方已经为你配置好了maven发布脚本,可以改也可以不改,不改的话执行

./gradlew publish

成功后,在下面目录可找到文件:

/Users/.m2/repository/com/tencent/shadow/dynamic /Users/.m2/repository/com/tencent/shadow/core

3.2 用Android Studio 分别打开

projects/sample/maven/host-project ,projects/sample/maven/manager-project ,projects/sample/maven/plugin-project三个目录。

其中host-project是宿主工程,manager-project是插件管理功能,plugin-project是插件项目.

注意这三个工程每一个都是一个单独的工程,都有各自的作用,接下来我们要做的就是分别仿照这三个工程的接入方式,进行配置

3.3 配置你自己的宿主工程

添加本地仓库

mavenLocal()

添加依赖

implementation project(':introduce-shadow-lib')

implementation "com.tencent.shadow.dynamic:host:$shadow_version"

Application中初始化

public class MyApplication extends Application {

    @Override

    public void onCreate() {

        super.onCreate();

        InitApplication.*onApplicationCreate*(this);

    }

}

清单文件中注册服务,以及插件容器Activity(其实这些已经在introduce-shadow-lib为我们做好了),但是我们不妨留意一下,因为这里配置了插件的服务进程,以及插件的容器页面

<service

            android:name=".MainPluginProcessService"

            android:process=":plugin" />
            
            ```
<!--container 注册
  注意configChanges需要全注册
  theme需要注册成透明

  这些类不打包在host中,打包在runtime中,以便减少宿主方法数增量
  -->
<activity
    android:name="com.tencent.shadow.sample.runtime.PluginDefaultProxyActivity"
    android:launchMode="standard"
    android:screenOrientation="portrait"
    android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
    android:hardwareAccelerated="true"
    android:theme="@style/PluginContainerActivity"
    android:process=":plugin" />

<activity
    android:name="com.tencent.shadow.sample.runtime.PluginSingleInstance1ProxyActivity"
    android:launchMode="singleInstance"
    android:screenOrientation="portrait"
    android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
    android:hardwareAccelerated="true"
    android:theme="@style/PluginContainerActivity"
    android:process=":plugin" />

<activity
    android:name="com.tencent.shadow.sample.runtime.PluginSingleTask1ProxyActivity"
    android:launchMode="singleTask"
    android:screenOrientation="portrait"
    android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
    android:hardwareAccelerated="true"
    android:theme="@style/PluginContainerActivity"
    android:process=":plugin" />

<provider
    android:authorities="com.tencent.shadow.contentprovider.authority.dynamic"
    android:name="com.tencent.shadow.core.runtime.container.PluginContainerContentProvider" />

宿主启动插件Activity

public static final int *FROM_ID_START_ACTIVITY* = 1001;

PluginManager pluginManager = InitApplication.*getPluginManager*();

pluginManager.enter(MainActivity.this, *FROM_ID_START_ACTIVITY*, new Bundle(), new EnterCallback() {

    @Override

    public void onShowLoadingView(View view) {

        MainActivity.this.setContentView(view);//显示Manager传来的Loading页面

    }

  


    @Override

    public void onCloseLoadingView() {

        MainActivity.this.setContentView(linearLayout);

    }

  


    @Override

    public void onEnterComplete() {

        v.setEnabled(true);

    }

});

这是一个接口方法,在manager工程中有对应的实现

@Override

public void enter(final Context context, long fromId, Bundle bundle, final EnterCallback callback) {

    if (fromId == Constant.*FROM_ID_START_ACTIVITY*) {

        bundle.putString(Constant.*KEY_PLUGIN_ZIP_PATH*, "/data/local/tmp/plugin-debug.zip");

        bundle.putString(Constant.*KEY_PLUGIN_PART_KEY*, "sample-plugin");

        bundle.putString(Constant.*KEY_ACTIVITY_CLASSNAME*, "com.tencent.shadow.sample.plugin.MainActivity");

        onStartActivity(context, bundle, callback);

    } else if (fromId == Constant.*FROM_ID_CALL_SERVICE*) {

        callPluginService(context);

    } else {

        throw new IllegalArgumentException("不认识的fromId=="   fromId);

    }

}

可以看到  bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME,"com.tencent.shadow.sample.plugin.MainActivity");传入了插件工程中的Activity

混淆配置

-keep class com.tencent.shadow.core.common.**{*;}

-keep class com.tencent.shadow.core.runtime.**{*;}

-keep class com.tencent.shadow.dynamic.host.**{*;}

3.4 配置你自己的插件管理工程manager-project

暂时原封不动的按照README的提示,进行打包,

./gradlew assembleDebug

并手动push到data/local/temp文件夹下(模拟下载过程)

adb push sample-manager/build/outputs/apk/debug/sample-manager-debug.apk /data/local/tmp

3.5 配置你自己的插件工程plugin-project

你可以像平时开发普通项目一样开发插件功能,但是要在插件工程项目,添加两个依赖包sample-loadersample-runtime

学新通

app目录中的build.gradle添加依赖:

    //Shadow Transform后业务代码会有一部分实际引用runtime中的类

    //如果不以compileOnly方式依赖,会导致其他Transform或者Proguard找不到这些类

    compileOnly "com.tencent.shadow.core:runtime:$shadow_version"

并在最下面添加如下配置

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'
                        buildTask = 'assemblePluginDebug'
                        apkName = 'plugin-app-plugin-debug.apk'
                        apkPath = 'plugin-app/build/outputs/apk/plugin/debug/plugin-app-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"
    }
}

混淆配置

#kotlin一般性配置 START

-dontwarn kotlin.**

-keepclassmembers class **$WhenMappings {

    <fields>;

}

-keepclassmembers class kotlin.Metadata {

    public <methods>;

}

#kotlin一般性配置 END

  


#kotlin优化性能 START

-assumenosideeffects class kotlin.jvm.internal.Intrinsics {

    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);

}

#kotlin优化性能 END

  


-keep class org.slf4j.**{*;}

-dontwarn org.slf4j.impl.**

  


-keep class com.tencent.shadow.dynamic.host.**{*;}

-keep class com.tencent.shadow.dynamic.impl.**{*;}

-keep class com.tencent.shadow.dynamic.loader.**{*;}

-keep class com.tencent.shadow.core.common.**{*;}

-keep class com.tencent.shadow.core.loader.**{*;}

-keep class com.tencent.shadow.core.runtime.**{*;}

  


-dontwarn  com.tencent.shadow.dynamic.host.**

-dontwarn  com.tencent.shadow.dynamic.impl.**

-dontwarn  com.tencent.shadow.dynamic.loader.**

-dontwarn  com.tencent.shadow.core.common.**

-dontwarn  com.tencent.shadow.core.loader.**

命令行运行,编译插件

./gradlew packageDebugPlugin

并push到data/local/tmp(模拟下载过程)

adb push build/plugin-debug.zip /data/local/tmp

至此所有配置操作完毕,可以即刻感受Shadow框架带给插件化开发的便利,这只是一个简单接入的一个小demo,是Shadow插件功能的冰山一角,它还有很多强大的功能,比如还有多插件发布,插件更新,插件使用宿主类等功能,可以等熟练使用了之后慢慢体会

学新通

注意事项

3.3,3.4,3.5分别对应三个不同的工程不要搞到一个工程,各自有各自的作用

AGP7.0以上引入Gradle插件可以暂时这样配置

buildscript {
    repositories {
        谷歌()
        mavenCentral()
        mavenLocal()
    }

    dependencies {
        classpath "com.tencent.shadow.core:gradle-plugin:local--SNAPSHOT"
    }
}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgahhea
系列文章
更多 icon
同类精品
更多 icon
继续加载