Summary of Android multi-channel packaging solutions

Meituan 's Walle solution: github.com/Meituan-Dia…

Tencent's VasDolly solution: github.com/Tencent/Vas…

packer-ng-plugin solution: github.com/mcxiaoke/pa…

From the Githubopen source maintenance situation, the packer-ng-pluginproject has stopped maintenance, Wallethe latest maintenance was 2 years ago, and VasDollythe latest maintenance was 5 months ago. From the perspective of open source maintenance, Tencent's VasDollysolution is even better.

Commercially available multi-channel automated packaging solution

VasDolly

Let's talk about the experience after use:

Because the latest VasDolly official version is v3.0.4, it directly integrates the latest version, without trying the historical old version. The project environment is:

dependencies {
classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.tencent.vasdolly:plugin:3.0.4'
}
distributionUrl=https://services.gradle.org/distributions/gradle-7.0.2-all.zip
复制代码

You can compile it successfully, and configure it according to the tutorial, you can print the corresponding channel package. DemoThe official one is this Gradlecompilation environment. Play 20 channel packs, the time can be controlled in about 1 minute.

However, for example the project environment is:

dependencies {
classpath "com.android.tools.build:gradle:4.1.3"
classpath 'com.tencent.vasdolly:plugin:3.0.4'
}
distributionUrl=https://services.gradle.org/distributions/gradle-6.6-all.zip
复制代码

Compiling the project will report this error:

Unable to load class 'com.android.build.api.extension.AndroidComponentsExtension'.
This is an unexpected error. Please file a bug containing the idea.log file.
复制代码

VasDolly implementation principle:

github.com/Tencent/Vas…

Generating Multichannel Packages with Gradle

If you directly compile and generate a multi-channel package, you must first configure the channel file, the output directory of the channel package, and the naming rules of the channel package:

channel{
    //指定渠道文件
    channelFile = file("/Users/leon/Downloads/testChannel.txt")
     //多渠道包的输出目录,默认为new File(project.buildDir,"channel")
    outputDir = new File(project.buildDir,"xxx")
    //多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}-${buildTime}
    apkNameFormat ='${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
    //快速模式:生成渠道包时不进行校验(速度可以提升10倍以上,默认为false)
    fastMode = false
    //buildTime的时间格式,默认格式:yyyyMMdd-HHmmss
    buildTimeDateFormat = 'yyyyMMdd-HH:mm:ss'
    //低内存模式(仅针对V2签名,默认为false):只把签名块、中央目录和EOCD读取到内存,不把最大头的内容块读取到内存,在手机上合成APK时,可以使用该模式
    lowMemory = false
}
复制代码

Among them, in the naming rules of multi-channel packages, the following fields can be used:

  • appName : the name of the current project
  • versionName : the versionName of the current Variant
  • versionCode : 当前Variant的versionCode
  • buildType : 当前Variant的buildType,即debug or release
  • flavorName : 当前的渠道名称
  • appId : 当前Variant的applicationId
  • buildTime : 当前编译构建日期时间,时间格式可以自定义,默认格式:yyyyMMdd-HHmmss

然后,通过 gradle channelDebuggradle channelRelease 命令分别生成 DebugRelease 的多渠道包。

为了方便临时生成渠道包进行测试,从v2.0.0开始支持添加渠道参数:gradle channelDebug(channelRelease) -Pchannels=yingyongbao,gamecenter,这里通过属性 channels 指定的渠道列表拥有更高的优先级,且和原始的文件方式是互斥的。

根据已有基础包重新生成多渠道包

若是根据已有基础包重新生成多渠道包,首先要配置渠道文件、基础包的路径和渠道包的输出目录:

rebuildChannel {
  //指定渠道文件
  channelFile = file("/Users/leon/Downloads/testReChannel.txt")
  // 已有APK文件地址(必填),如new File(project.rootDir, "/baseApk/app_base.apk"),文件名中的base将被替换为渠道名
  baseApk = 已有APK文件地址(必填)
  //默认为new File(project.buildDir, "rebuildChannel")
  outputDir = 渠道包输出目录
  //快速模式:生成渠道包时不进行校验(速度可以提升10倍以上,默认为false)
  fastMode = false
  //低内存模式(仅针对V2签名,默认为false):只把签名块、中央目录和EOCD读取到内存,不把最大头的内容块读取到内存,在手机上合成APK时,可以使用该模式
  lowMemory = false
}
复制代码

通过命令行生成渠道包、读取渠道信息:

github.com/Tencent/Vas…

读取渠道信息

通过 helper 类库中的 ChannelReaderUtil 类读取渠道信息。

String channel = ChannelReaderUtil.getChannel(getApplicationContext());
复制代码

如果没有渠道信息,那么这里返回 null,开发者需要自己判断。


Walle

先说使用后的体验:

Walle 官方库已经2年多没更新,v1.1.7 为最新的版本。打20个渠道包,时间也可以控制在1分钟左右。 项目环境为:

dependencies {
classpath 'com.android.tools.build:gradle:4.1.3'
classpath 'com.meituan.android.walle:plugin:1.1.7'
}
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-6.6-all.zip
复制代码

即可成功编译,并且按教程配置,可以打出对应的渠道包。

Walle 实现原理:

tech.meituan.com/2017/01/13/…


最后总结:

  • If the project was packaged ASmanually , configure some channel package related information in andApp in the main project . Now that you have used the scheme of , you should also make changes to the relevant code in your own project. E.g:build.gradleAndroidManifest.xmlVasDollyWalle
  1. AndroidManifest.xml, Umeng SDKneeds to get the channel name of the app
<meta-data
       android:name="UMENG_CHANNEL"
       android:value="${UMENG_CHANNEL_VALUE}" />
复制代码
  1. In the main Appproject build.gradle, if the following code is written:
  flavorDimensions "versionCode", "serverUrl"
复制代码
           applicationVariants.all { variant ->
                variant.outputs.all { output ->
                    def fileName
                    if (variant.buildType.name == "release") {
                        fileName = "XXAPP-${variant.productFlavors[0].name}-${variant.versionName}-Android.apk"
                    } else {
                        fileName = "XXAPP-Android.apk"
                    }
                    outputFileName = fileName
                }
            }
复制代码
productFlavors {
        yingyongbao {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"]
        }
        huawei {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "huawei"]
        }
        xiaomi {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }
        oppo {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "oppo"]
        }
        vivo {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "vivo"]
        }
        weibo {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "weibo"]
        }
        bzhan {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "bzhan"]
        }
        toutiao {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "toutiao"]
        }
        guangdiantong {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "guangdiantong"]
        }
        baidu {
            dimension "versionCode"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
        }
        urlTest {
            dimension "serverUrl"
            buildConfigField("int", "SERVER_TYPE", "1")
        }
        urlOnline {
            dimension "serverUrl"
            buildConfigField("int", "SERVER_TYPE", "2")
        }
    }
复制代码

The configuration related to these channel packages will conflict with the plan of , so it should be VasDollywritten according to the writing method in the official tutorial ofWalleVasDollyWalle

  • Because the packer-ng-pluginproject has stopped maintenance, and the V2 signature scheme is not supported, so I didn't try this situation.

Guess you like

Origin juejin.im/post/7119409569670889509