Build Variant — що це, build type і product flavor в Android

Автор: IT Sectr Опубліковано: 2026-05-30 Час читання: 9 хв

Build Variant в Android-розробці — це комбінація build type і product flavor, яка визначає, як буде зібрано 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. Наприклад, для flavor free/paid і типів debug/release буде створено 4 варіанти: 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 — можна.

Ключова практична відмінність: defaultConfig в build.gradle застосовується до всіх Variants, але може бути перевизначений в productFlavors і buildTypes. BuildConfigField, доданий в buildType, видимий у всіх 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 Variants в build.gradle

Пріоритет конфігурацій

Налаштування Build Variants виконується в блоці android файлу build.gradle рівня модуля. Спочатку оголошуються buildTypes з їхніми параметрами, потім flavorDimensions і productFlavors. Gradle автоматично створює варіанти на основі цих оголошень. Кожен варіант успадковує defaultConfig модуля, перевизначаючи вказані поля. Порядок оголошення впливає на пріоритет: buildTypes застосовуються після productFlavors.

Для доступу до конкретного Build Variant в Gradle-скриптах використовується android.applicationVariants (для app модуля) або android.libraryVariants (для бібліотечного модуля). Це колекція, по якій можна ітеруватися та змінювати конфігурацію кожного варіанту в рантаймі конфігурації. Наприклад, можна програмно додавати buildConfigField для всіх варіантів, що містять слово «demo».

Android Gradle Plugin 8.x додав підтримку onVariants — більш чисте API для налаштування варіантів через лямбди. Старе API (variantOutput, variantFilter) позначено як deprecated. Рекомендується використовувати 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, віддаючи пріоритет variant-специфічним.

Source sets для Build Variant будуються по ланцюжку: src/main/src/flavor/src/type/src/flavorType/. Наприклад, для paidRelease спочатку застосовується main, потім paid, потім release, потім paidRelease. Кожен наступний source set перевизначає попередній. Це означає, що src/release/res/values/strings.xml перевизначить ті ж рядки з src/paid/, але src/paidRelease/res/ — ще більш пріоритетний.

Використання source sets для варіантів — рекомендований спосіб кастомізації ресурсів. Замість того щоб перевіряти BuildConfig.FLAVOR в коді і гілкувати логіку, можна просто помістити різні файли в різні source sets. Наприклад, іконки для free і paid версій кладуться в src/free/res/ і src/paid/res/ відповідно, а AndroidManifest з різними дозволами — в src/free/AndroidManifest.xml і src/paid/AndroidManifest.xml. Це чистіше, швидше (ресурси компілюються, а не перевіряються в runtime) і безпечніше (не можна випадково включити платну функціональність у безкоштовній версії через баг у коді).

Build Variant у багатомодульних проектах

У багатомодульних проектах кожен модуль (бібліотека) може мати власні Build Variants. AGP автоматично синхронізує варіанти: якщо app-модуль збирає paidRelease, всі залежні бібліотеки також збираються в їхніх варіантах, що відповідають paidRelease. Проблема виникає, коли бібліотека не має product flavors, але app-модуль має — тоді бібліотека збирається один раз (release або debug залежно від типу).

Для бібліотечних модулів Build Variant за замовчуванням збігається з Build Type app-модуля, оскільки в бібліотек немає product flavors. Якщо бібліотека повинна підлаштовуватися під flavor app-модуля, необхідно оголосити ті ж flavorDimensions і productFlavors в бібліотеці. AGP зіставляє flavor за повним збігом імені. Gradle рекомендує синхронізувати flavors через build-конфігурацію в кореневому проекті за допомогою subprojects або Convention Plugins.

Починаючи з AGP 8.1, бібліотеки можуть публікувати multiple variants — опублікувати в maven-репозиторій всі варіанти бібліотеки одночасно. Це вирішує проблему, коли app-модуль використовує paid flavor, а бібліотека опублікована тільки для free. Multiple variants publishing (MVP) дозволяє залежному проекту вибрати потрібний варіант автоматично. Для включення MVP потрібно додати publishing { multipleVariants { ... } } в build.gradle бібліотеки.

Фільтрація та вимкнення варіантів

Динамічна фільтрація через CI/CD

Іноді необхідно вимкнути частину Build Variants — наприклад, якщо комбінація mockRelease не має сенсу (мок-сервер не повинен потрапляти в продакшн). Gradle надає variantFilter — DSL-блок, в якому можна перевіряти властивості кожного варіанту і вимикати його через setIgnore(true). VariantFilter застосовується на етапі конфігурації, до створення завдань, тому вимкнений варіант не генерує assemble та install завдання.

Фільтрація також корисна для прискорення збірки. Якщо в проекті 8 варіантів, а розробник працює тільки над одним, решта 7 варіантів все одно проходять конфігурацію. При використанні variantFilter вимкнені варіанти не створюють завдань, що скорочує час конфігурації на 30-50% для проектів з 6+ flavor-вимірами. В CI/CD можна динамічно фільтрувати варіанти через параметри командного рядка -PbuildOnly=paidRelease.

groovy
android {
    variantFilter { variant ->
        // Вимикаємо mock для release і demo для production
        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 автоматично підставить значення. Це дозволяє встановити обидва варіанти на один пристрій.

Чи можна використовувати Build Variants в iOS?

В iOS аналогом Build Variants є комбінація Scheme + Configuration. Xcode Schemes налаштовуються через конфігурації Debug/Release з різними параметрами. Для кількох версій (free/paid) використовуються Build Configurations і Preprocessor Macros. На Android концепція формалізована суворіше і вбудована в Gradle.

Build Variant впливає на розмір APK?

Так, кожен варіант може мати різний розмір APK. debug-збірки включають налагоджувальну інформацію, SDK і непідтримувані ресурси. Release-збірки з minification і resource shrinking дають мінімальний розмір. 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 створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також