想象你是在一个汽车工厂工作:
-
你的 App 就是一辆汽车。
-
buildTypes
(构建类型): 这指的是你生产汽车的 目的 或 阶段。debug
(调试): 这是你工厂内部测试用的样车。它装满了诊断工具(Logcat 日志、调试器连接)、没有做任何优化(方便快速修改和测试)、甚至可能有些特殊标识(比如应用名后面加_debug
)。生产速度快,但不适合给客户。release
(发布): 这就是真正要卖给客户的量产车。它去掉了所有测试工具、经过了严格优化(代码混淆minifyEnabled
、资源压缩shrinkResources
)、性能更好、体积更小、安全性更高(可能做了代码签名)。生产速度慢,但质量高。- 你还可以自定义其他类型,比如
staging
(预发布),用于给测试团队做最后测试,配置介于debug
和release
之间。
-
productFlavors
(产品风味): 这指的是你生产汽车的 不同版本或型号。它们共享同一个核心底盘和引擎(你的核心 App 代码和资源src/main
),但有不同的配置、功能或外观。-
例子 1:免费版 vs 付费版 (
free
vspaid
)free
:可能包含广告 SDK、某些高级功能被锁定或移除、应用图标上有个 “Free” 角标。paid
:没有广告、解锁所有功能、可能有专属主题或图标。
-
例子 2:不同客户定制 (
customerA
vscustomerB
)customerA
:使用 A 公司的品牌颜色、Logo、后端 API 地址。customerB
:使用 B 公司的品牌颜色、Logo、不同的后端 API 地址。
-
例子 3:不同分发渠道 (
googleplay
vsamazon
)- 可能需要集成不同的应用内支付 SDK 或处理不同的商店政策。
-
核心思想:
productFlavors
让你能用同一套核心代码,生成多个不同版本的 App。
-
-
变体 (
Variants
):buildTypes
×productFlavors
-
这才是真正神奇的地方!变体就是
buildTypes
和productFlavors
组合 的结果。 -
每个可能的组合都会生成一个独特的 App 版本 (APK/AAB)。
-
命名规则:
[flavor][BuildType]
(例如:freeDebug
,freeRelease
,paidDebug
,paidRelease
)。在 Android Studio 的Build Variants
窗口里你会看到这些名字。 -
如何组合架构?
-
想象一个表格:
构建类型 \ 产品风味 free
(免费版)paid
(付费版)debug
(调试)freeDebug
paidDebug
release
(发布)freeRelease
paidRelease
-
你的构建系统 (Gradle) 会自动为表格中的 每一个格子 创建一个构建任务和最终的输出包。
-
-
-
具体如何编译(组合源代码和资源)?
Gradle 在编译一个特定的变体(比如paidRelease
) 时,会按照一个优先级顺序合并来自不同地方的代码、资源和配置 (AndroidManifest.xml
)。理解这个“覆盖”机制是关键:-
主源集 (
main
): 这是基础。它包含所有变体共享的代码、资源、AndroidManifest.xml
。就像一个公共的零件仓库。 -
构建类型源集 (
buildTypes
): 例如src/debug
或src/release
。这里的文件会覆盖或补充main
中的同名文件。比如:debug/AndroidManifest.xml
里可以添加android:debuggable="true"
。release/java/
下可以放一些只在发布版本需要的工具类(虽然更常见做法是用build.gradle
条件判断)。
-
产品风味源集 (
productFlavors
): 例如src/free
或src/paid
。这里的文件同样会覆盖或补充main
中的文件,并且覆盖buildTypes
源集中的文件(如果存在同名冲突)。free/res/values/strings.xml
可以定义app_name
为 “MyApp (Free)”。paid/res/values/colors.xml
可以定义品牌主色调为金色。paid/java/
下可以放付费版独有的功能类。
-
变体源集 (
variants
): 这是最具体的层级。例如src/freeDebug
或src/paidRelease
。这里的文件优先级最高,会覆盖前面所有层级(main
,buildType
,flavor
) 的同名文件。- 通常用得不多,但在极少数需要为某个特定组合(如
freeDebug
) 做非常特殊调整时使用。
- 通常用得不多,但在极少数需要为某个特定组合(如
-
依赖项 (
dependencies
): 在build.gradle
文件中,你可以声明某些依赖库只对特定的构建类型或产品风味生效:dependencies { // 所有变体都依赖 implementation 'com.android.support:appcompat-v7:28.0.0' // 仅 debug 变体依赖 (例如 LeakCanary) debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' // 仅 free 风味依赖 (例如某个广告 SDK) freeImplementation 'com.google.android.gms:play-services-ads:20.4.0' // 仅 paid 风味依赖 (例如某个支付 SDK) paidImplementation 'com.example.premium:payment-sdk:1.0.0' }
编译流程简述(以
paidRelease
为例):-
Gradle 决定要构建
paidRelease
变体。 -
收集所有源文件:
- 合并
main
的所有代码和资源。 - 用
release
源集中的文件覆盖/补充main
中同路径同名的文件。 - 用
paid
源集中的文件覆盖/补充前面合并结果中同路径同名的文件(包括release
覆盖过来的)。 - 最后用
paidRelease
源集中的文件(如果有)覆盖/补充前面所有结果。
- 合并
-
合并
AndroidManifest.xml
文件:同样遵循main
+release
+paid
+paidRelease
的覆盖顺序。 -
应用
build.gradle
中release
构建类型的配置(混淆、压缩、签名配置等)。 -
应用
build.gradle
中paid
产品风味的配置(如果有,比如applicationIdSuffix
)。 -
根据依赖声明,只包含
implementation
,releaseImplementation
,paidImplementation
的库(不包含debugImplementation
或freeImplementation
)。 -
执行编译(Java/Kotlin -> DEX)、资源处理(AAPT2)、打包(APK/AAB)、签名(对于 release)等标准 Android 构建步骤。
-
输出最终的
paidRelease
APK 或 AAB 文件。
-
-
Flavor Dimensions (风味维度) - 更复杂的组合
-
有时一个维度(比如
version
)不够。你可能同时需要区分version
(免费/付费) 和target
(手机/平板) 或者region
(国内/国际)。 -
风味维度 (
flavorDimensions
) 让你可以定义多个独立的分类标准。 -
定义维度: 在
build.gradle
的android
块中声明维度名:flavorDimensions "version", "target"
flavorDimensions
列表中位置靠后的维度,会覆盖靠前的维度! -
在维度下定义风味:
productFlavors { free { dimension "version" // 属于 "version" 维度 ... } paid { dimension "version" ... } phone { dimension "target" // 属于 "target" 维度 ... } tablet { dimension "target" ... } }
-
变体组合: Gradle 会做笛卡尔积,组合所有维度下的每一个风味。上面的例子会产生:
freePhoneDebug
,freePhoneRelease
freeTabletDebug
,freeTabletRelease
paidPhoneDebug
,paidPhoneRelease
paidTabletDebug
,paidTabletRelease
-
源集目录: 源集目录可以更细化,例如:
src/freePhone/
(覆盖free/
和phone/
)src/paidTabletRelease/
(覆盖所有)
-
-
为什么需要这个机制?
- 高效管理多版本: 避免为每个小变体维护一个完全独立的项目。
- 代码复用最大化: 共享核心逻辑 (
main
),差异化部分隔离 (flavors
,buildTypes
)。 - 自动化构建: Gradle 自动处理所有组合的构建任务。
- 隔离配置: 不同环境(开发/生产)、不同客户/版本(免费/付费)的 API 密钥、服务器地址、功能开关、资源等严格分开,避免配置错误。
- 定制化发布: 轻松为不同应用商店、不同客户群体打包不同的 APK/AAB。
总结:
buildTypes
: 控制 App 的构建目的 (开发调试 vs 发布上线),影响优化、调试能力和签名。productFlavors
: 定义 App 的不同版本或定制 (免费版/付费版/客户A版/客户B版),允许代码、资源和配置的差异化。- 变体 (
Variants
): 是buildTypes
和productFlavors
(可能跨多个维度flavorDimensions
) 的所有可能组合。每个变体都是一个独立的、可构建的 App 版本。 - 编译组合: Gradle 按照
main
<buildType
<productFlavor
<variant
的优先级顺序合并代码、资源和清单文件,并应用相应的构建配置和依赖。
通俗比喻终极版:
-
想象你开了一家 T 恤衫工厂 (
buildTypes
×productFlavors
) 。 -
buildTypes
是生产线:sample
线:快速打样,布料普通,缝线松散(方便拆改),有内部标签 (debug
)。production
线:精工细作,用最好布料,缝线牢固,有精美吊牌 (release
)。
-
productFlavors
是 T 恤的 设计款式:logoA
: 印公司 A 的 Logo (free
/ 客户 A)。logoB
: 印公司 B 的 Logo (paid
/ 客户 B)。vneck
: V 领款式 (tablet
适配)。crewneck
: 圆领款式 (phone
适配)。
-
变体 (
Variants
) 就是最终生产出来的具体 T 恤:logoA sample vneck
(freeDebug tablet
): 给公司 A 看的 V 领样品衫。logoB production crewneck
(paidRelease phone
): 卖给公司 B 的圆领量产衫。
-
组合过程: 工人(Gradle)拿到订单(构建
paidRelease phone
):- 拿一件基础白T (
main
)。 - 送到
production
线:按量产标准缝好 (release
配置)。 - 送到
logoB
设计组:印上 B 公司 Logo (paid
资源/代码)。 - 送到
crewneck
设计组:做成圆领 (phone
适配/代码)。 - (如果有
paidReleasePhone
特别设计组,最后再加工一下)。 - 打包发货 (输出 APK/AAB)。
- 拿一件基础白T (