Build Variant — 是什么、build type 和 product flavor 在 Android 中

作者: IT Sectr 发布日期: 2026-05-30 阅读时间: 9 分钟

在 Android 开发中,Build Variant 是构建类型和产品风味的组合,它决定了 APK 或 AAB 如何构建:使用哪些参数、资源和代码。每个构建变体都是一个独立的 Gradle 配置,具有自己的 applicationId、签名密钥和包含的依赖项。根据 Google Android Developers, 2025,正确配置 Build Variants 通过为每个变体排除不必要的资源,可将构建时间缩短 40%。构建变体系统是现代 Android 项目中配置管理的基础。

要点

  • Build Variant — 一个 Build Type 和一个 Product Flavor 的组合。
  • Build Type 设置构建模式:debug(调试)或 release(发布)。
  • Product Flavor 定义应用的版本:free、paid、demo、enterprise。
  • Gradle 自动为每个 Build Variant 生成任务,包括 install 和 assemble。
  • 资源和代码 可以通过相应的 source sets 为每个变体覆盖。

什么是 Build Variant?

Build Variant — 是一个 Build Type 和一个 Product Flavor 组合的结果。如果项目中未定义 Product Flavor,则 Build Variant 与 Build Type 一致。Gradle 会自动生成所有 FlavorDimensions、Product Flavors 和 Build Types 的笛卡尔积作为完整变体集。例如,对于 free/paid flavor 和 debug/release 类型,将创建 8 个变体:freeDebug、freeRelease、paidDebug、paidRelease。

每个 Build Variant 都有自己的名称,格式为 <Flavor><Type>,flavor 首字母大写。对于此变体,Gradle 会生成单独的任务:assembleFreeDebug、installFreeDebug、bundleFreeRelease。在 Android Studio 中,可以通过 Build Variants 面板(View → Tool Windows → Build Variants)在变体之间切换。变体的选择会影响编译哪些代码、包含哪些资源以及创建哪个 APK/AAB。

Build Variants 系统解决了三个关键任务:分离不同环境(dev/staging/production)的配置、创建应用的多个版本(free/paid)以及构建的 A/B 测试。如果没有 Build Variants,开发人员必须手动切换标志和配置,这会导致人为错误。根据 Gradle Inc., 2024 的研究,在具有三个或更多部署环境的项目中,引入 Build Variants 可将构建错误数量减少 60%。

Gradle 如何生成变体

AGP(Android Gradle Plugin)在配置阶段计算所有组合。如果项目有两个维度,分别有两个和三个 flavor,Gradle 将创建 2 × 2 × 3 = 12 个组合,乘以 Build Types 的数量(通常为 2)。每个组合都有一个唯一的名称和一组任务。AGP 会自动为每个变体添加 source set:src/freeDebug/src/paidRelease/,以及通用化的 src/free/src/debug/。资源读取优先级:variant → flavor → type → main。

groovy
// 示例:4 个 Build Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// 总共:2 × 2 × 2 = 8 个变体

android {
    flavorDimensions "version", "server"

    productFlavors {
        demo { dimension "version" }
        prod { dimension "version" }
        mock { dimension "server" }
        live { dimension "server" }
    }
}

Build Type 和 Product Flavor:区别

Build Type 决定如何编译应用程序——带或不带调试信息,带或不带优化,使用什么签名。Product Flavor 决定编译什么——哪个产品版本。Build Type — 是构建机制(debug、release、staging)。Product Flavor — 是产品变体(free、paid、enterprise、demo)。这两个概念是正交的:任何 Build Type 都可以应用于任何 Product Flavor。

Build Type 默认包括 debug(debuggable=true、minification=false、signing=debug.keystore)和 release(debuggable=false、minification=true、signing=production.keystore)。Product Flavor 默认只有一个,没有名称(实际上是 main source set)。开发人员可以添加自己的 Build Types(例如,“staging” 具有 debuggable=true 和 minification=true)和任意数量的 Product Flavors。区别还在于 Build Type 不能分组到维度中,而 Product Flavor 可以。

关键的实践区别:build.gradle 中的 defaultConfig 适用于所有 Variants,但可以在 productFlavors 和 buildTypes 中被覆盖。在 buildType 中添加的 BuildConfigField 在该类型的所有 flavor 中可见,而在 productFlavor 中添加的则在所有该 flavor 的类型中可见。如果字段同时在两处定义——buildType 具有优先级(在链中最后应用)。

比较表

特征Build TypeProduct Flavor
目的如何构建构建什么
示例debug、release、stagingfree、paid、demo、enterprise
默认debug + release一个(main)
Source Setsrc/debug/、src/release/src/free/、src/paid/
维度flavorDimensions
应用在 flavor 之后,覆盖在 defaultConfig 之后
BuildConfigField覆盖 flavor覆盖 defaultConfig

在 build.gradle 中配置 Build Variants

配置的优先级

Build Variants 的配置在模块级别的 build.gradle 文件的 android 块中执行。首先声明 buildTypes 及其参数,然后是 flavorDimensions 和 productFlavors。Gradle 基于这些声明自动创建变体。每个变体继承模块的 defaultConfig,覆盖指定的字段。声明顺序影响优先级:buildTypes 在 productFlavors 之后应用。

为了在 Gradle 脚本中访问特定的 Build Variant,使用 android.applicationVariants(对于 app 模块)或 android.libraryVariants(对于库模块)。这是一个集合,可以在配置时对其进行迭代并更改每个变体的配置。例如,可以以编程方式为所有包含 “demo” 单词的变体添加 buildConfigField。

Android Gradle Plugin 8.x 添加了对 onVariants 的支持——通过 lambda 配置变体的更清晰 API。旧 API(variantOutput、variantFilter)已被标记为弃用。建议为库模块使用 onVariants 配合 onEach。从 variantOutput 迁移到 onVariants — 是从 AGP 7.x 升级到 8.x 时的推荐步骤。

groovy
android {
    buildTypes {
        debug {
            debuggable true
            minification false
            signingConfig signingConfigs.debug
        }
        release {
            debuggable false
            minification true
            proguardFiles "proguard-rules.pro"
            signingConfig signingConfigs.release
        }
        staging {
            debuggable true
            minification true
            versionNameSuffix "-staging"
        }
    }

    flavorDimensions "tier", "region"

    productFlavors {
        free { dimension "tier" }
        paid { dimension "tier" }
        us { dimension "region" }
        eu { dimension "region" }
    }
}

android.onVariants { variant ->
    if (variant.name.contains("Demo")) {
        variant.setEnabled(false)
    }
}

Source Sets 和资源覆盖

每个 Build Variant 都有自己的 source sets 层次结构——包含源代码、资源和清单的目录。Source set 位于 src/<variantName>/(例如 src/freeDebug/)并且可以包含 java/、res/、AndroidManifest.xml、assets/。如果文件存在于变体的 source set 中,它将覆盖来自主 source set(src/main/)的同名文件。对于资源,使用合并而非替换——系统合并来自所有活动 source sets 的资源,优先处理特定于变体的资源。

Build Variant 的 source sets 按链构建:src/main/src/flavor/src/type/src/flavorType/。例如,对于 paidRelease,首先应用 main,然后是 paid,然后是 release,最后是 paidRelease。每个后续 source set 都覆盖前一个。这意味着 src/release/res/values/strings.xml 将覆盖来自 src/paid/ 的相同字符串,但 src/paid/release/res/ 优先级更高。

为变体使用 source sets — 是自定义资源的推荐方式。与其在代码中检查 BuildConfig.FLAVOR 并分支逻辑,不如简单地将不同文件放置在不同的 source sets 中。例如,free 和 paid 版本的图标分别放在 src/free/res/src/paid/res/ 中,具有不同权限的 AndroidManifest 则放在 src/free/AndroidManifest.xmlsrc/paid/AndroidManifest.xml 中。这更清晰、更快(资源在编译时处理,而非运行时检查)且更安全(不会因代码错误而意外在免费版本中包含付费功能)。

多模块项目中的 Build Variant

在多模块项目中,每个模块(库)都可以有自己的 Build Variants。AGP 自动同步变体:如果 app 模块编译 paidRelease,所有依赖库也在其与 paidRelease 对应的变体中编译。问题出现在库没有 product flavors 但 app 模块有时——此时库仅编译一次(release 或 debug,取决于类型)。

对于库模块,Build Variant 默认与 app 模块的 Build Type 一致,因为库没有 product flavors。如果库需要适应 app 模块的 flavor,则必须在库中声明相同的 flavorDimensions 和 productFlavors。AGP 通过名称完全匹配来匹配 flavor。Gradle 建议通过根项目中的构建配置使用 subprojects 或 Convention Plugins 来同步 flavor。

从 AGP 8.1 开始,库可以发布 multiple variants——将库的所有变体同时发布到 maven 仓库。这解决了 app 模块使用 paid flavor 但库仅发布为 free 时的问题。Multiple variants publishing(MVP)允许依赖项目自动选择所需的变体。要启用 MVP,需要在库的 build.gradle 中添加 publishing { multipleVariants { ... } }

变体的过滤和禁用

通过 CI/CD 动态过滤

有时需要禁用部分 Build Variants——例如,如果 mockRelease 组合没有意义(mock 服务器不应进入生产环境)。Gradle 提供 variantFilter——一个 DSL 块,可以在其中检查每个变体的属性并通过 setIgnore(true) 禁用它。VariantFilter 在配置阶段,在创建任务之前应用,因此禁用的变体不会生成 assemble 和 install 任务。

过滤对于加速构建也很有用。如果项目有 8 个变体而开发人员只处理其中一个,其余 7 个变体仍然会通过配置阶段。使用 variantFilter 时,禁用的变体不会创建任务,这可以将具有 6+ flavor 维度的项目的配置时间减少 30-50%。在 CI/CD 中,可以通过命令行参数 -PbuildOnly=paidRelease 动态过滤变体。

groovy
android {
    variantFilter { variant ->
        // 为 release 禁用 mock,为 production 禁用 demo
        def names = variant.flavors*.name
        def isMock = names.contains("mock")
        def isDemo = names.contains("demo")
        def isRelease = variant.buildType.name == "release"

        if ((isMock && isRelease) || (isDemo && !isMock)) {
            variant.setIgnore(true)
        }
    }
}

// 通过参数动态过滤
if (project.hasProperty("buildOnly")) {
    def target = project.property("buildOnly")
    android.variantFilter { variant ->
        variant.setIgnore(variant.name != target)
    }
}

常见问题

可以创建多少个 Build Variants?

没有限制,但 Gradle 会创建所有 flavor 和类型的 笛卡尔积。如果您有 3 个维度各 3 个 flavor 和 3 个 build type——将得到 27 个变体。过多的变体会减慢配置速度。建议一个模块中不超过 10-12 个变体。

为什么需要 flavorDimensions?

flavorDimensions 将 Product Flavors 分组到独立的轴上。例如,维度 “tier”(free、paid)和 “region”(us、eu)。如果没有维度,所有 flavor 属于一个轴,Gradle 将从所有 flavor 中只选择一个(不能将 free+us 和 paid+eu 作为单独的变体)。

如何为变体覆盖 applicationId?

在 productFlavor 或 buildType 块中指定 applicationId。例如,对于 free 版本:free { applicationId "com.example.app.free" }。在清单中使用 ${applicationId}——Gradle 会自动替换值。这允许在同一设备上安装两个变体。

可以在 iOS 中使用 Build Variants 吗?

在 iOS 中,Build Variants 的对应物是 Scheme + Configuration 的组合。Xcode Schemes 通过具有不同参数的 Debug/Release 配置进行配置。对于多个版本(free/paid),使用 Build Configurations 和 Preprocessor Macros。在 Android 中,概念更加形式化并内置于 Gradle 中。

Build Variant 会影响 APK 大小吗?

是的,每个变体可以有不同大小的 APK。Debug 构建包含调试信息、SDK 和 不支持的资源。带有最小化和资源缩减的 Release 构建提供最小大小。Product Flavor 也会影响:没有付费库的 free 版本将比 paid 版本小这些库的大小。

总结

  • Build Variant — 一个 Build Type 和一个 Product Flavor 的组合,决定构建配置。
  • Build Type 管理构建模式(debug/release/staging),而 Product Flavor 管理产品版本(free/paid)。
  • Source sets 允许为每个构建变体覆盖代码、资源和清单。
  • VariantFilter 禁用不必要的组合,将 Gradle 配置速度提高 30-50%。
  • 多模块项目 需要在所有模块之间同步 flavor 或使用 multiple variants publishing。
  • BuildConfigField 和 source sets — 两种在变体之间自定义行为的干净方式。
  • 建议:一个项目中不要创建超过 10-12 个变体,有意义地分组维度。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读