Build Variant i Android-utveckling är en kombination av build type och product flavor som bestämmer hur APK eller AAB ska byggas: med vilka parametrar, resurser och kod. Varje kompileringsvariant är en separat Gradle-konfiguration med eget applicationId, signeringsnycklar och inkluderade beroenden. Enligt Google Android Developers, 2025 minskar korrekt konfiguration av Build Variants kompileringstiden med 40% genom att utesluta onödiga resurser för varje variant. Systemet med kompileringsvarianter är grunden för konfigurationshantering i moderna Android-projekt.
Huvudpunkter
Build Variant — är resultatet av kombinationen av en Build Type och en Product Flavor. Om ingen Product Flavor är definierad i projektet sammanfaller Build Variant med Build Type. Gradle genererar automatiskt den fullständiga uppsättningen varianter som den kartesiska produkten av alla FlavorDimensions, Product Flavors och Build Types. Till exempel, för flavor free/paid och typerna debug/release skapas 8 varianter: freeDebug, freeRelease, paidDebug, paidRelease.
Varje Build Variant får ett eget namn i formatet <Flavor><Type> med flavor med stor bokstav. För denna variant genererar Gradle separata uppgifter: assembleFreeDebug, installFreeDebug, bundleFreeRelease. I Android Studio är växling mellan varianter tillgänglig via panelen Build Variants (View → Tool Windows → Build Variants). Valet av variant påverkar vilken kod som kompileras, vilka resurser som inkluderas och vilken APK/AAB som skapas.
Systemet Build Variants löser tre viktiga uppgifter: separation av konfigurationer för olika miljöer (dev/staging/production), skapande av flera versioner av appen (free/paid) och A/B-testning av byggen. Utan Build Variants skulle utvecklare behöva manuellt växla flaggor och konfigurationer, vilket leder till mänskliga fel. Enligt forskning från Gradle Inc., 2024 minskar implementeringen av Build Variants antalet kompileringsfel med 60% i projekt med tre eller fler distributionsmiljöer.
AGP (Android Gradle Plugin) beräknar alla kombinationer i konfigurationsfasen. Om projektet har två dimensioner med två respektive tre flavor, skapar Gradle 2 × 2 × 3 = 12 kombinationer, multiplicerat med antalet Build Types (vanligtvis 2). Varje kombination får ett unikt namn och en uppsättning uppgifter. AGP lägger automatiskt till en source set för varje variant: src/freeDebug/, src/paidRelease/, samt generaliserade src/free/ och src/debug/. Prioriteten för resursläsning: variant → flavor → type → main.
// Exempel: 4 Build Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// Totalt: 2 × 2 × 2 = 8 varianter
android {
flavorDimensions "version", "server"
productFlavors {
demo { dimension "version" }
prod { dimension "version" }
mock { dimension "server" }
live { dimension "server" }
}
}
Build Type bestämmer hur appen kompileras — med felsökningsinformation eller utan, med optimering eller utan, med vilken signering. Product Flavor bestämmer vad som kompileras — vilken version av produkten. Build Type — är kompileringsmekanismen (debug, release, staging). Product Flavor — är produktvarianten (free, paid, enterprise, demo). Båda begreppen är ortogonala: vilken Build Type som helst kan tillämpas på vilken Product Flavor som helst.
Build Type inkluderar som standard debug (debuggable=true, minification=false, signing=debug.keystore) och release (debuggable=false, minification=true, signing=production.keystore). Product Flavor är som standard en, utan namn (egentligen main source set). Utvecklaren kan lägga till egna Build Types (t.ex. “staging” med debuggable=true och minification=true) och Product Flavors i valfritt antal. Skillnaden ligger också i att Build Type inte kan grupperas i dimensioner, medan Product Flavor kan.
Den viktigaste praktiska skillnaden: defaultConfig i build.gradle tillämpas på alla Variants, men kan åsidosättas i productFlavors och buildTypes. BuildConfigField som läggs till i buildType är synlig i alla flavor av denna typ, och den som läggs till i productFlavor — i alla typer av denna flavor. Om fältet definieras både där och där — har buildType prioritet (tillämpas sist i kedjan).
| Egenskap | Build Type | Product Flavor |
|---|---|---|
| Syfte | Hur man kompilerar | Vad man kompilerar |
| Exempel | debug, release, staging | free, paid, demo, enterprise |
| Standard | debug + release | en (main) |
| Source Set | src/debug/, src/release/ | src/free/, src/paid/ |
| Dimensioner | nej | flavorDimensions |
| Tillämpning | efter flavor, åsidosätter | efter defaultConfig |
| BuildConfigField | åsidosätter flavor | åsidosätter defaultConfig |
Konfigurationen av Build Variants utförs i android-blocket i build.gradle-filen på modulnivå. Först deklareras buildTypes med sina parametrar, sedan flavorDimensions och productFlavors. Gradle skapar automatiskt varianter baserat på dessa deklarationer. Varje variant ärver modulens defaultConfig och åsidosätter angivna fält. Deklarationsordningen påverkar prioriteten: buildTypes tillämpas efter productFlavors.
För åtkomst till en specifik Build Variant i Gradle-skript används android.applicationVariants (för app-modulen) eller android.libraryVariants (för biblioteksmodulen). Detta är en samling som kan itereras över och konfigurationen för varje variant kan ändras under konfigurationstiden. Till exempel kan buildConfigField programmatiskt läggas till för alla varianter som innehåller ordet “demo”.
Android Gradle Plugin 8.x lade till stöd för onVariants — ett renare API för att konfigurera varianter via lambdas. Det gamla API:et (variantOutput, variantFilter) är markerat som föråldrat. Det rekommenderas att använda onVariants tillsammans med onEach för biblioteksmoduler. Migrering från variantOutput till onVariants — rekommenderat steg vid uppdatering av AGP från 7.x till 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)
}
}
Varje Build Variant får sin egen hierarki av source sets — kataloger med källkod, resurser och manifest. Source set finns i src/<variantName>/ (t.ex. src/freeDebug/) och kan innehålla java/, res/, AndroidManifest.xml, assets/. Om en fil finns i variantens source set åsidosätter den filen med samma namn från huvud-source set (src/main/). För resurser fungerar sammanslagning, inte ersättning — systemet kombinerar resurser från alla aktiva source sets och ger prioritet till variantspecifika.
Source sets för Build Variant byggs i en kedja: src/main/ → src/flavor/ → src/type/ → src/flavorType/. Till exempel, för paidRelease tillämpas först main, sedan paid, sedan release, sedan paidRelease. Varje efterföljande source set åsidosätter den föregående. Detta innebär att src/release/res/values/strings.xml åsidosätter samma strängar från src/paid/, men src/paid/release/res/ är ännu mer prioriterad.
Att använda source sets för varianter — det rekommenderade sättet att anpassa resurser. Istället för att kontrollera BuildConfig.FLAVOR i koden och förgrena logik, kan olika filer helt enkelt placeras i olika source sets. Till exempel placeras ikoner för free- och paid-versionerna i src/free/res/ respektive src/paid/res/, och AndroidManifest med olika behörigheter — i src/free/AndroidManifest.xml och src/paid/AndroidManifest.xml. Detta är renare, snabbare (resurser kompileras, kontrolleras inte vid körning) och säkrare (betald funktionalitet kan inte oavsiktligt aktiveras i gratisversionen på grund av ett fel i koden).
I multimodulprojekt kan varje modul (bibliotek) ha egna Build Variants. AGP synkroniserar automatiskt varianter: om app-modulen kompilerar paidRelease, kompileras även alla beroende bibliotek i sina varianter som motsvarar paidRelease. Problemet uppstår när biblioteket inte har product flavors, men app-modulen har — då kompileras biblioteket en gång (release eller debug beroende på typ).
För biblioteksmoduler sammanfaller Build Variant som standard med Build Type för app-modulen, eftersom bibliotek inte har product flavors. Om biblioteket måste anpassas till app-modulens flavor, måste samma flavorDimensions och productFlavors deklareras i biblioteket. AGP matchar flavor genom fullständig namnmatchning. Gradle rekommenderar att synkronisera flavor via byggkonfigurationen i rotprojektet med subprojects eller Convention Plugins.
Från och med AGP 8.1 kan bibliotek publicera multiple variants — publicera alla varianter av biblioteket samtidigt i ett maven-förvar. Detta löser problemet när app-modulen använder paid flavor, men biblioteket endast är publicerat för free. Multiple variants publishing (MVP) gör det möjligt för det beroende projektet att automatiskt välja den nödvändiga varianten. För att aktivera MVP måste publishing { multipleVariants { ... } } läggas till i bibliotekets build.gradle.
Ibland är det nödvändigt att inaktivera en del av Build Variants — till exempel om kombinationen mockRelease inte är meningsfull (mock-servern bör inte nå produktion). Gradle tillhandahåller variantFilter — ett DSL-block där egenskaperna för varje variant kan kontrolleras och inaktiveras via setIgnore(true). VariantFilter tillämpas i konfigurationsfasen, före skapandet av uppgifter, så en inaktiverad variant genererar inte assemble- och install-uppgifter.
Filtrering är också användbart för att påskynda kompilering. Om projektet har 8 varianter och utvecklaren bara arbetar med en, går de återstående 7 varianterna ändå igenom konfiguration (configuration phase). Vid användning av variantFilter skapar inaktiverade varianter inga uppgifter, vilket minskar konfigurationstiden med 30-50% för projekt med 6+ flavordimensioner. I CI/CD kan varianter dynamiskt filtreras via kommandoradsparametrar -PbuildOnly=paidRelease.
android {
variantFilter { variant ->
// Inaktivera mock för release och demo för produktion
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)
}
}
}
// Dynamisk filtrering via parametrar
if (project.hasProperty("buildOnly")) {
def target = project.property("buildOnly")
android.variantFilter { variant ->
variant.setIgnore(variant.name != target)
}
}
Vanliga frågor
Det finns inga begränsningar, men Gradle skapar den kartesiska produkten av alla flavor och typer. Om du har 3 dimensioner med 3 flavor och 3 build type — får du 27 varianter. För många varianter saktar ner konfigurationen. Rekommenderas inte mer än 10-12 varianter i en modul.
flavorDimensions grupperar Product Flavors i oberoende axlar. Till exempel, dimension “tier” (free, paid) och “region” (us, eu). Utan dimensioner tillhör alla flavor en axel och Gradle väljer bara en flavor från alla (man kan inte ha free+us och paid+eu som separata varianter).
I productFlavor- eller buildType-blocket anger du applicationId. Till exempel för free-versionen: free { applicationId "com.example.app.free" }. I manifestet använder du ${applicationId} — Gradle ersätter automatiskt värdet. Detta gör det möjligt att installera båda varianterna på en enhet.
I iOS är motsvarigheten till Build Variants kombinationen Scheme + Configuration. Xcode Schemes konfigureras via Debug/Release-konfigurationer med olika parametrar. För flera versioner (free/paid) används Build Configurations och Preprocessor Macros. I Android är konceptet mer formaliserat och inbyggt i Gradle.
Ja, varje variant kan ha olika APK-storlek. Debug-byggen innehåller felsökningsinformation, SDK och ej stödda resurser. Release-byggen med minifiering och resursminskning ger minimal storlek. Product Flavor påverkar också: free-versionen utan betalda bibliotek blir mindre än paid-versionen med storleken på dessa bibliotek.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också