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. Ово је чистије, брже (ресурси се компајлирају, а не проверавају у runtime-у) и сигурније (не може се случајно укључити плаћена функционалност у бесплатној верзији због грешке у коду).
У вишемодулним пројектима сваки модул (библиотека) може имати сопствене 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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође