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 Github
open source maintenance situation, the packer-ng-plugin
project has stopped maintenance, Walle
the latest maintenance was 2 years ago, and VasDolly
the latest maintenance was 5 months ago. From the perspective of open source maintenance, Tencent's VasDolly
solution is even better.
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. Demo
The official one is this Gradle
compilation 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:
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 channelDebug
、gradle channelRelease
命令分别生成 Debug
和 Release
的多渠道包。
为了方便临时生成渠道包进行测试,从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
}
复制代码
通过命令行生成渠道包、读取渠道信息:
读取渠道信息
通过 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 实现原理:
最后总结:
- If the project was packaged
AS
manually , 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.gradle
AndroidManifest.xml
VasDolly
Walle
AndroidManifest.xml
, UmengSDK
needs to get the channel name of the app
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
复制代码
- In the main
App
projectbuild.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 VasDolly
written according to the writing method in the official tutorial ofWalle
VasDolly
Walle
- Because the
packer-ng-plugin
project has stopped maintenance, and the V2 signature scheme is not supported, so I didn't try this situation.