Ang Build Variant sa pag-develop ng Android ay isang kombinasyon ng build type at product flavor na tumutukoy kung paano bubuo ang APK o AAB: sa anong mga parameter, resources at code. Ang bawat variant ng compilation ay isang hiwalay na Gradle configuration na may sariling applicationId, signing keys at kasamang dependencies. Ayon sa Google Android Developers, 2025, ang tamang configuration ng Build Variants ay nagbabawas ng oras ng compilation ng hanggang 40% sa pamamagitan ng pagbukod ng hindi kinakailangang resources para sa bawat variant. Ang sistema ng mga variant ng compilation ay pundasyon ng pamamahala ng configuration sa mga modernong Android project.
Mga pangunahing punto
Build Variant — ay ang resulta ng kombinasyon ng isang Build Type at isang Product Flavor. Kung walang Product Flavor na tinukoy sa proyekto, ang Build Variant ay kasabay ng Build Type. Awtomatikong bumubuo ang Gradle ng buong set ng mga variant bilang Cartesian product ng lahat ng FlavorDimensions, Product Flavors at Build Types. Halimbawa, para sa flavor free/paid at mga type debug/release, gagawin ang 8 variant: freeDebug, freeRelease, paidDebug, paidRelease.
Ang bawat Build Variant ay nakakakuha ng sariling pangalan sa format na <Flavor><Type> na may malaking titik ang flavor. Para sa variant na ito, bumubuo ang Gradle ng magkakahiwalay na gawain: assembleFreeDebug, installFreeDebug, bundleFreeRelease. Sa Android Studio, ang paglipat sa pagitan ng mga variant ay magagamit sa pamamagitan ng panel na Build Variants (View → Tool Windows → Build Variants). Ang pagpili ng variant ay nakakaapekto sa kung aling code ang na-compile, kung aling resources ang kasama at kung aling APK/AAB ang nilikha.
Ang sistema ng Build Variants ay lumulutas ng tatlong pangunahing gawain: paghihiwalay ng mga configuration para sa iba't ibang kapaligiran (dev/staging/production), paglikha ng maraming bersyon ng app (free/paid) at A/B testing ng mga build. Kung wala ang Build Variants, ang mga developer ay kailangang manu-manong magpalipat ng mga flag at configuration, na humahantong sa mga pagkakamali ng human factor. Ayon sa pananaliksik ng Gradle Inc., 2024, ang pagpapatupad ng Build Variants ay nagbabawas ng bilang ng mga error sa compilation ng 60% sa mga proyektong may tatlo o higit pang deployment environment.
AGP (Android Gradle Plugin) ay kinakalkula ang lahat ng kombinasyon sa configuration phase. Kung ang proyekto ay may dalawang dimensyon na may dalawa at tatlong flavor, gagawa ang Gradle ng 2 × 2 × 3 = 12 kombinasyon, na i-multiply sa bilang ng Build Types (karaniwang 2). Ang bawat kombinasyon ay nakakakuha ng natatanging pangalan at set ng mga gawain. Awtomatikong nagdaragdag ang AGP ng source set para sa bawat variant: src/freeDebug/, src/paidRelease/, pati na rin ang generalisadong src/free/ at src/debug/. Priyoridad ng pagbasa ng resources: variant → flavor → type → main.
// Halimbawa: 4 Build Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// Kabuuan: 2 × 2 × 2 = 8 variant
android {
flavorDimensions "version", "server"
productFlavors {
demo { dimension "version" }
prod { dimension "version" }
mock { dimension "server" }
live { dimension "server" }
}
}
Build Type ay tumutukoy kung paano naka-compile ang app — may debugging information o wala, may optimization o wala, sa anong signing. Product Flavor ay tumutukoy kung ano ang na-compile — aling bersyon ng produkto. Build Type — ay ang mekanismo ng compilation (debug, release, staging). Product Flavor — ay ang variant ng produkto (free, paid, enterprise, demo). Ang parehong konsepto ay orthogonal: anumang Build Type ay maaaring ilapat sa anumang Product Flavor.
Ang Build Type bilang default ay may kasamang debug (debuggable=true, minification=false, signing=debug.keystore) at release (debuggable=false, minification=true, signing=production.keystore). Ang Product Flavor bilang default ay isa, walang pangalan (sa katunayan main source set). Maaaring magdagdag ang developer ng sariling Build Types (halimbawa, “staging” na may debuggable=true at minification=true) at Product Flavors sa anumang bilang. Ang pagkakaiba ay nasa katotohanan din na ang Build Type ay hindi maaaring pangkatin sa mga dimensyon, ngunit ang Product Flavor ay maaari.
Ang pangunahing praktikal na pagkakaiba: defaultConfig sa build.gradle ay inilalapat sa lahat ng Variants, ngunit maaaring ma-override sa productFlavors at buildTypes. Ang BuildConfigField na idinagdag sa buildType ay nakikita sa lahat ng flavor ng type na ito, at ang idinagdag sa productFlavor — sa lahat ng type ng flavor na ito. Kung ang field ay tinukoy pareho doon at dito — ang buildType ang may priyoridad (inilalapat ng huli sa chain).
| Katangian | Build Type | Product Flavor |
|---|---|---|
| Layunin | Paano mag-compile | Ano ang i-compile |
| Halimbawa | debug, release, staging | free, paid, demo, enterprise |
| Default | debug + release | isa (main) |
| Source Set | src/debug/, src/release/ | src/free/, src/paid/ |
| Dimensyon | hindi | flavorDimensions |
| Paglalapat | pagkatapos ng flavor, nag-o-override | pagkatapos ng defaultConfig |
| BuildConfigField | nag-o-override ng flavor | nag-o-override ng defaultConfig |
Ang pag-configure ng Build Variants ay ginagawa sa android block ng build.gradle file sa antas ng module. Una ay idineklara ang buildTypes kasama ang kanilang mga parameter, pagkatapos ang flavorDimensions at productFlavors. Awtomatikong gumagawa ang Gradle ng mga variant batay sa mga deklarasyong ito. Ang bawat variant ay nagmamana ng defaultConfig ng module, na nag-o-override ng mga tinukoy na field. Ang pagkakasunud-sunod ng deklarasyon ay nakakaapekto sa priyoridad: ang buildTypes ay inilalapat pagkatapos ng productFlavors.
Para sa pag-access sa isang partikular na Build Variant sa Gradle scripts, ginagamit ang android.applicationVariants (para sa app module) o android.libraryVariants (para sa library module). Ito ay isang koleksyon na maaaring i-iterate at baguhin ang configuration ng bawat variant sa oras ng configuration. Halimbawa, maaaring mag-programmatically magdagdag ng buildConfigField para sa lahat ng variant na naglalaman ng salitang “demo”.
Ang Android Gradle Plugin 8.x ay nagdagdag ng suporta para sa onVariants — isang mas malinis na API para sa pag-configure ng mga variant sa pamamagitan ng lambda. Ang lumang API (variantOutput, variantFilter) ay minarkahan bilang deprecated. Inirerekomenda na gamitin ang onVariants kasama ng onEach para sa mga module ng library. Ang paglipat mula variantOutput patungo sa onVariants — inirerekomendang hakbang kapag nag-a-update ng AGP mula 7.x patungo 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)
}
}
Ang bawat Build Variant ay nakakakuha ng sariling hierarchy ng source sets — mga direktoryo na may source code, resources at manifest. Ang source set ay matatagpuan sa src/<variantName>/ (halimbawa, src/freeDebug/) at maaaring maglaman ng java/, res/, AndroidManifest.xml, assets/. Kung ang isang file ay umiiral sa source set ng variant, ito ay nag-o-override ng file na may parehong pangalan mula sa pangunahing source set (src/main/). Para sa resources, gumagana ang pagsasama, hindi pagpapalit — pinagsasama ng system ang mga resources mula sa lahat ng aktibong source sets, na nagbibigay ng priyoridad sa mga spesipiko sa variant.
Ang source sets para sa Build Variant ay binuo sa chain: src/main/ → src/flavor/ → src/type/ → src/flavorType/. Halimbawa, para sa paidRelease, unang inilalapat ang main, pagkatapos ang paid, pagkatapos ang release, pagkatapos ang paidRelease. Ang bawat susunod na source set ay nag-o-override sa nauna. Ito ay nangangahulugan na ang src/release/res/values/strings.xml ay mag-o-override ng parehong mga string mula sa src/paid/, ngunit ang src/paid/release/res/ ay mas priyoridad.
Ang paggamit ng source sets para sa mga variant — ang inirerekomendang paraan upang i-customize ang resources. Sa halip na suriin ang BuildConfig.FLAVOR sa code at mag-branch ng logic, maaaring ilagay ang iba't ibang file sa iba't ibang source sets. Halimbawa, ang mga icon para sa free at paid na bersyon ay inilalagay sa src/free/res/ at src/paid/res/ ayon sa pagkakabanggit, at ang AndroidManifest na may iba't ibang pahintulot — sa src/free/AndroidManifest.xml at src/paid/AndroidManifest.xml. Ito ay mas malinis, mas mabilis (ang resources ay na-compile, hindi sinusuri sa runtime) at mas ligtas (hindi maaaring aksidenteng maisama ang bayad na functionality sa libreng bersyon dahil sa bug sa code).
Sa mga proyektong multi-module, ang bawat module (library) ay maaaring magkaroon ng sariling Build Variants. Awtomatikong nagsi-sync ang AGP ng mga variant: kung ang app module ay nag-compile ng paidRelease, ang lahat ng dependent library ay na-compile din sa kanilang mga variant na tumutugma sa paidRelease. Ang problema ay lumilitaw kapag ang library ay walang product flavors, ngunit ang app module ay mayroon — kung gayon ang library ay na-compile nang isang beses (release o debug depende sa type).
Para sa mga module ng library, ang Build Variant bilang default ay kasabay ng Build Type ng app module, dahil ang mga library ay walang product flavors. Kung ang library ay dapat umangkop sa flavor ng app module, kailangang ideklara ang parehong flavorDimensions at productFlavors sa library. Itinutugma ng AGP ang flavor sa pamamagitan ng buong pagkakatugma ng pangalan. Inirerekomenda ng Gradle na i-sync ang mga flavor sa pamamagitan ng build configuration sa root project gamit ang subprojects o Convention Plugins.
Simula sa AGP 8.1, ang mga library ay maaaring mag-publish ng multiple variants — i-publish ang lahat ng variant ng library nang sabay-sabay sa maven repository. Ito ay lumulutas ng problema kapag ang app module ay gumagamit ng paid flavor, ngunit ang library ay nai-publish lamang para sa free. Ang multiple variants publishing (MVP) ay nagbibigay-daan sa dependent project na awtomatikong pumili ng kinakailangang variant. Para i-activate ang MVP, kailangang magdagdag ng publishing { multipleVariants { ... } } sa build.gradle ng library.
Minsan kailangang i-disable ang bahagi ng Build Variants — halimbawa, kung ang kombinasyong mockRelease ay walang saysay (ang mock server ay hindi dapat pumunta sa production). Nagbibigay ang Gradle ng variantFilter — isang DSL block kung saan maaaring suriin ang mga property ng bawat variant at i-disable ito sa pamamagitan ng setIgnore(true). Ang VariantFilter ay inilalapat sa configuration phase, bago ang paglikha ng mga gawain, kaya ang naka-disable na variant ay hindi bumubuo ng mga gawaing assemble at install.
Ang pag-filter ay kapaki-pakinabang din para sa pagpapabilis ng compilation. Kung ang proyekto ay may 8 variant at ang developer ay nagtatrabaho lamang sa isa, ang natitirang 7 variant ay dumadaan pa rin sa configuration (configuration phase). Kapag gumagamit ng variantFilter, ang mga naka-disable na variant ay hindi lumilikha ng mga gawain, na nagbabawas ng oras ng configuration ng 30-50% para sa mga proyektong may 6+ flavor dimensyon. Sa CI/CD, ang mga variant ay maaaring dynamic na i-filter sa pamamagitan ng command line parameters -PbuildOnly=paidRelease.
android {
variantFilter { variant ->
// I-disable ang mock para sa release at demo para sa 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)
}
}
}
// Dynamic na pag-filter sa pamamagitan ng mga parameter
if (project.hasProperty("buildOnly")) {
def target = project.property("buildOnly")
android.variantFilter { variant ->
variant.setIgnore(variant.name != target)
}
}
Mga madalas itanong
Walang limitasyon, ngunit ang Gradle ay gumagawa ng Cartesian product ng lahat ng flavor at type. Kung mayroon kang 3 dimensyon na may 3 flavor at 3 build type — makakakuha ka ng 27 variant. Masyadong maraming variant ang nagpapabagal ng configuration. Inirerekomenda na hindi hihigit sa 10-12 variant sa isang module.
Ang flavorDimensions ay nagpapangkat ng Product Flavors sa mga independiyenteng axis. Halimbawa, dimensyon “tier” (free, paid) at “region” (us, eu). Kung walang dimensyon, lahat ng flavor ay kabilang sa isang axis at ang Gradle ay pumipili lamang ng isang flavor mula sa lahat (hindi maaaring magkaroon ng free+us at paid+eu bilang magkahiwalay na variant).
Sa productFlavor o buildType block, tukuyin ang applicationId. Halimbawa, para sa free na bersyon: free { applicationId "com.example.app.free" }. Sa manifest, gamitin ang ${applicationId} — awtomatikong papalitan ng Gradle ang halaga. Ito ay nagpapahintulot na mai-install ang parehong variant sa isang device.
Sa iOS, ang katumbas ng Build Variants ay kombinasyon ng Scheme + Configuration. Ang Xcode Schemes ay naka-configure sa pamamagitan ng Debug/Release configuration na may iba't ibang parameter. Para sa maraming bersyon (free/paid) ginagamit ang Build Configurations at Preprocessor Macros. Sa Android, ang konsepto ay mas pormal at naka-embed sa Gradle.
Oo, ang bawat variant ay maaaring may iba't ibang laki ng APK. Ang debug builds ay may kasamang debugging information, SDK at hindi suportadong resources. Ang release builds na may minification at resource shrinking ay nagbibigay ng minimal na laki. Ang Product Flavor ay may epekto rin: ang free na bersyon na walang bayad na library ay magiging mas maliit kaysa sa paid na bersyon sa laki ng mga library na ito.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din