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. Ако в проекта не е дефиниран Product Flavor, Build Variant съвпада с Build Type. Gradle автоматично генерира пълния набор от варианти като декартово произведение на всички FlavorDimensions, Product Flavors и Build Types. Например, за flavor free/paid и типовете 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% в проекти с три или повече среди за разполагане.
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.
// Пример: 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 — е механизмът за компилация (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 Type | Product Flavor |
|---|---|---|
| Предназначение | Как да компилираме | Какво да компилираме |
| Примери | debug, release, staging | free, paid, demo, enterprise |
| По подразбиране | debug + release | един (main) |
| Source Set | src/debug/, src/release/ | src/free/, src/paid/ |
| Измерения | не | flavorDimensions |
| Прилагане | след flavor, презаписва | след defaultConfig |
| BuildConfigField | презаписва flavor | презаписва defaultConfig |
Настройката на 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) е маркирано като остаряло. Препоръчва се използването на onVariants заедно с onEach за библиотечни модули. Миграцията от variantOutput към onVariants — препоръчителна стъпка при актуализиране на AGP от 7.x на 8.x.
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)
}
}
Всеки Build Variant получава собствена йерархия от source sets — директории с изходен код, ресурси и манифест. Source set се намира в src/<variantName>/ (например, src/freeDebug/) и може да съдържа java/, res/, AndroidManifest.xml, assets/. Ако файл съществува в source set на варианта, той презаписва файла със същото име от основния source set (src/main/). За ресурси работи сливане, а не замяна — системата комбинира ресурси от всички активни source sets, давайки приоритет на специфичните за варианта.
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/paid/release/res/ е още по-приоритетен.
Използването на source sets за варианти — препоръчителният начин за персонализиране на ресурси. Вместо да проверявате BuildConfig.FLAVOR в кода и да разклонявате логиката, можете просто да поставите различни файлове в различни source sets. Например, иконите за free и paid версии се поставят съответно в src/free/res/ и src/paid/res/, а AndroidManifest с различни разрешения — в src/free/AndroidManifest.xml и src/paid/AndroidManifest.xml. Това е по-чисто, по-бързо (ресурсите се компилират, не се проверяват по време на изпълнение) и по-безопасно (не може случайно да се включи платена функционалност в безплатната версия поради грешка в кода).
В мултимодулни проекти всеки модул (библиотека) може да има свои 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 препоръчва синхронизиране на flavor чрез конфигурацията за изграждане в основния проект с помощта на subprojects или Convention Plugins.
От AGP 8.1 нататък библиотеките могат да публикуват multiple variants — да публикуват всички варианти на библиотеката едновременно в maven хранилище. Това решава проблема, когато модулът app използва paid flavor, но библиотеката е публикувана само за free. Multiple variants publishing (MVP) позволява на зависимия проект автоматично да избере необходимия вариант. За активиране на MVP трябва да се добави publishing { multipleVariants { ... } } в build.gradle на библиотеката.
Понякога е необходимо да се изключи част от Build Variants — например, ако комбинацията mockRelease няма смисъл (mock сървърът не трябва да достига до продукция). Gradle предоставя variantFilter — DSL блок, в който могат да се проверят свойствата на всеки вариант и да се изключи чрез setIgnore(true). VariantFilter се прилага във фазата на конфигурация, преди създаването на задачи, така че изключеният вариант не генерира задачи assemble и install.
Филтрирането е полезно и за ускоряване на компилацията. Ако проектът има 8 варианта и разработчикът работи само върху един, останалите 7 варианта все пак преминават през конфигурация (configuration phase). При използване на variantFilter изключените варианти не създават задачи, което намалява времето за конфигурация с 30-50% за проекти с 6+ flavor измерения. В CI/CD вариантите могат да бъдат динамично филтрирани чрез параметри на командния ред -PbuildOnly=paidRelease.
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)
}
}
Често задавани въпроси
Няма ограничения, но Gradle създава декартово произведение на всички flavor и типове. Ако имате 3 измерения с по 3 flavor и 3 build type — ще получите 27 варианта. Твърде много варианти забавят конфигурацията. Препоръчват се не повече от 10-12 варианта в един модул.
flavorDimensions групират Product Flavors в независими оси. Например, измерение «tier» (free, paid) и «region» (us, eu). Без измерения всички flavor принадлежат към една ос и Gradle ще избере само един flavor от всички (не можете да имате free+us и paid+eu като отделни варианти).
В блока productFlavor или buildType посочете applicationId. Например, за free версия: free { applicationId "com.example.app.free" }. В манифеста използвайте ${applicationId} — Gradle автоматично ще замести стойността. Това позволява инсталиране на двата варианта на едно устройство.
В iOS аналогът на Build Variants е комбинацията Scheme + Configuration. Xcode Schemes се конфигурират чрез Debug/Release конфигурации с различни параметри. За множество версии (free/paid) се използват Build Configurations и Preprocessor Macros. В Android концепцията е по-формализирана и вградена в Gradle.
Да, всеки вариант може да има различен размер на APK. Debug компилациите включват информация за отстраняване на грешки, SDK и неподдържани ресурси. Release компилациите с минификация и намаляване на ресурсите дават минимален размер. Product Flavor също влияе: free версията без платени библиотеки ще бъде по-малка от paid версията с размера на тези библиотеки.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също