5、构建类型与变体:BuildType、ProductFlavor、FlavorDimension、VariantFilter、签名配置
各位同学,今天我们来聊聊 Gradle 构建中一个非常核心的概念——构建变体。说白了,就是怎么用一套代码,打出不同环境、不同渠道的包。
我记得刚入行那会儿,公司要打测试包、正式包、不同渠道的包。那时候我还在用最原始的方式——手动改代码里的常量。每次打包前都要检查一遍,生怕忘了改回来。后来学了 Gradle 的变体机制,才发现原来可以这么优雅。
5.1 BuildType:构建类型
BuildType 是最基础的维度。它定义了构建过程中的一些属性,比如是否开启混淆、是否可调试、签名用哪个等等。
默认情况下,Android Gradle 插件会给我们创建两个 BuildType:debug 和 release。当然,你可以自己加更多。
android {
buildTypes {
debug {
// 可调试,默认就是 true
debuggable true
// 使用默认的 debug 签名
signingConfig signingConfigs.debug
}
release {
// 不可调试
debuggable false
// 开启混淆
minifyEnabled true
// 指定混淆规则文件
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
// 指定签名配置
signingConfig signingConfigs.release
}
staging {
// 我自己习惯加一个 staging 类型,用于预发布环境
debuggable true
minifyEnabled false
// 可以继承 release 的配置
initWith release
// 然后覆盖某些属性
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
}
}
}
小技巧:使用 initWith 可以快速复制一个已有的 BuildType 配置,然后只修改你需要改的部分。我在项目中经常用这个来创建 staging 或 beta 类型。
5.2 ProductFlavor:产品风味
ProductFlavor 是另一个维度。它通常用来区分不同的渠道、不同的产品变体。比如免费版和付费版,或者不同市场的包。
你想想看,如果每个渠道都要手动改代码,那得多累?ProductFlavor 就是来解决这个问题的。
android {
flavorDimensions "version", "channel"
productFlavors {
free {
dimension "version"
applicationIdSuffix ".free"
versionNameSuffix "-free"
}
paid {
dimension "version"
applicationIdSuffix ".paid"
versionNameSuffix "-paid"
}
google {
dimension "channel"
}
huawei {
dimension "channel"
}
xiaomi {
dimension "channel"
}
}
}
配置完之后,Gradle 会自动生成一系列任务。比如 assembleFreeGoogleDebug、assemblePaidHuaweiRelease 等等。每个变体都可以有自己的源代码目录、资源文件、AndroidManifest.xml。
重点:ProductFlavor 和 BuildType 组合起来,就形成了构建变体(Build Variant)。比如 free + debug、paid + release。每个变体都是一个独立的 APK。
5.3 FlavorDimension:风味维度
当你有多个 ProductFlavor 时,就需要用 FlavorDimension 来管理它们之间的关系。说白了,就是给 flavor 分组。
为什么要分组?因为如果不分组,所有 flavor 会两两组合,产生很多变体。比如上面例子中,free、paid、google、huawei、xiaomi 如果不分组,就会产生 2 × 3 = 6 种组合。但如果你想让 free 和 paid 是一组,渠道是另一组,那就需要维度。
android {
flavorDimensions "version", "channel"
productFlavors {
free {
dimension "version"
}
paid {
dimension "version"
}
google {
dimension "channel"
}
huawei {
dimension "channel"
}
}
}
这样组合出来的变体就是:freeGoogle、freeHuawei、paidGoogle、paidHuawei。每个维度取一个值,组合成最终的变体。
我曾经踩过的坑:有一次我忘了给某个 flavor 指定 dimension,结果 Gradle 报错说 flavor 没有关联维度。后来我养成了习惯,只要定义了多个 flavor,就一定先声明 flavorDimensions。
5.4 VariantFilter:变体过滤器
有时候,某些变体组合是没有意义的。比如免费版不需要发布到华为市场,或者调试版不需要打所有渠道的包。这时候就可以用 VariantFilter 来过滤掉不需要的变体。
android {
variantFilter { variant ->
def names = variant.flavors*.name
// 如果 flavor 列表包含 "free" 和 "huawei",就跳过
if (names.contains("free") && names.contains("huawei")) {
setIgnore(true)
}
// 如果是 debug 类型,只保留 google 渠道
if (variant.buildType.name == "debug" && !names.contains("google")) {
setIgnore(true)
}
}
}
嗯,这里要注意:setIgnore(true) 会让 Gradle 跳过这个变体的所有任务。这样在打包时就不会生成无用的 APK,能节省不少时间。
个人经验:我在一个大项目中,有 4 个维度、十几个 flavor,组合出来上百个变体。用 VariantFilter 过滤掉无用的组合后,打包时间从 40 分钟降到了 15 分钟。效果立竿见影。
5.5 签名配置:SigningConfig
签名配置是打包的最后一步。没有签名,APK 就装不到设备上(调试模式除外)。
签名配置通常在 android 块中定义,然后在 BuildType 中引用。
android {
signingConfigs {
debug {
// 默认使用 Android SDK 自带的 debug 证书
storeFile file("debug.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
release {
// 正式签名,建议从环境变量读取,不要硬编码
storeFile file(System.getenv("KEYSTORE_PATH") ?: "release.keystore")
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
signingConfig signingConfigs.release
}
}
}
安全提醒:千万不要把正式签名的密码硬编码在 build.gradle 中。我曾经见过有人把密钥文件直接提交到 Git 仓库,结果被全网公开。建议使用环境变量,或者在 CI/CD 系统中配置。
5.6 知识体系图
下面这张图展示了构建变体的核心逻辑,我画了很久,希望能帮你理清思路。
5.7 实战:如何选择变体
在实际开发中,我一般这样组织变体:
- BuildType:只保留 debug 和 release。staging 用 flavor 来实现。
- FlavorDimension:按「环境」和「渠道」两个维度划分。
- VariantFilter:过滤掉 debug + 所有渠道的组合,只保留 debug + 默认渠道。
- 签名配置:debug 用默认签名,release 从 CI 环境变量读取。
这样做的好处是,变体数量可控,打包速度快,而且不容易出错。
总结一下:构建变体是 Gradle 构建中最强大的功能之一。它让你用一套代码,管理多个产品形态。BuildType 控制构建过程,ProductFlavor 控制产品特性,FlavorDimension 管理 flavor 关系,VariantFilter 做减法,SigningConfig 保证安全。把这五个概念吃透了,你的构建脚本就能应对绝大多数场景。
公众号:蓝海资料掘金营,微信deep3321