Build Variant — co to jest, build type i product flavor w Androidzie

Autor: IT Sectr Opublikowano: 2026-05-30 Czas czytania: 9 min

Build Variant w tworzeniu aplikacji na Androida to kombinacja build type i product flavor, która określa, jak zostanie zbudowany APK lub AAB: z jakimi parametrami, zasobami i kodem. Każdy wariant kompilacji stanowi oddzielną konfigurację Gradle z własnym applicationId, kluczami podpisywania i dołączonymi zależnościami. Według danych Google Android Developers, 2025, prawidłowa konfiguracja Build Variants skraca czas kompilacji o 40% dzięki wykluczeniu niepotrzebnych zasobów dla każdego wariantu. System wariantów kompilacji stanowi podstawę zarządzania konfiguracją we współczesnych projektach Android.

Najważniejsze

  • Build Variant — kombinacja jednego Build Type i jednego Product Flavor.
  • Build Type określa tryb kompilacji: debug (debugowanie) lub release (wydanie).
  • Product Flavor definiuje wersję aplikacji: free, paid, demo, enterprise.
  • Gradle automatycznie generuje zadania dla każdego Build Variant, w tym install i assemble.
  • Zasoby i kod mogą być nadpisywane dla każdego wariantu przez odpowiednie source sets.

Co to jest Build Variant?

Build Variant — to wynik kombinacji jednego Build Type i jednego Product Flavor. Jeśli w projekcie nie zdefiniowano Product Flavor, Build Variant pokrywa się z Build Type. Gradle automatycznie generuje pełny zestaw wariantów jako iloczyn kartezjański wszystkich FlavorDimensions, Product Flavors i Build Types. Na przykład dla flavor free/paid i typów debug/release zostanie utworzone 8 wariantów: freeDebug, freeRelease, paidDebug, paidRelease.

Każdy Build Variant otrzymuje własną nazwę w formacie <Flavor><Type> z wielkiej litery flavor. Dla tego wariantu Gradle generuje osobne zadania: assembleFreeDebug, installFreeDebug, bundleFreeRelease. W Android Studio przełączanie między wariantami jest dostępne przez panel Build Variants (View → Tool Windows → Build Variants). Wybór wariantu wpływa na to, który kod jest kompilowany, które zasoby są dołączane i który APK/AAB jest tworzony.

System Build Variants rozwiązuje trzy kluczowe zadania: rozdzielenie konfiguracji dla różnych środowisk (dev/staging/production), tworzenie wielu wersji aplikacji (free/paid) i A/B testowanie kompilacji. Bez Build Variants programiści musieliby ręcznie przełączać flagi i konfiguracje, co prowadzi do błędów czynnika ludzkiego. Według badań Gradle Inc., 2024, wdrożenie Build Variants zmniejsza liczbę błędów kompilacji o 60% w projektach z trzema lub więcej środowiskami wdrożeniowymi.

Jak Gradle generuje warianty

AGP (Android Gradle Plugin) oblicza wszystkie kombinacje na etapie konfiguracji. Jeśli w projekcie są dwa wymiary z odpowiednio dwoma i trzema flavor, Gradle utworzy 2 × 2 × 3 = 12 kombinacji, pomnożonych przez liczbę Build Types (zwykle 2). Każda kombinacja otrzymuje unikalną nazwę i zestaw zadań. AGP automatycznie dodaje source set dla każdego wariantu: src/freeDebug/, src/paidRelease/, a także uogólnione src/free/ i src/debug/. Priorytet odczytu zasobów: variant → flavor → type → main.

groovy
// Przykład: 4 Build Varianty
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// Razem: 2 × 2 × 2 = 8 wariantów

android {
    flavorDimensions "version", "server"

    productFlavors {
        demo { dimension "version" }
        prod { dimension "version" }
        mock { dimension "server" }
        live { dimension "server" }
    }
}

Build Type i Product Flavor: różnice

Build Type określa jak kompilować aplikację — z informacjami debugowania czy bez, z optymalizacją czy bez, z jakim podpisywaniem. Product Flavor określa co kompilować — którą wersję produktu. Build Type — to mechanizm kompilacji (debug, release, staging). Product Flavor — to wariant produktu (free, paid, enterprise, demo). Oba pojęcia są ortogonalne: każdy Build Type można zastosować do każdego Product Flavor.

Build Type domyślnie obejmuje debug (debuggable=true, minification=false, signing=debug.keystore) i release (debuggable=false, minification=true, signing=production.keystore). Product Flavor domyślnie jest jeden, bez nazwy (faktycznie main source set). Deweloper może dodawać własne Build Types (np. „staging“ z debuggable=true i minification=true) i Product Flavors w dowolnej liczbie. Różnica polega również na tym, że Build Type nie można grupować w wymiary, a Product Flavor — można.

Kluczowa praktyczna różnica: defaultConfig w build.gradle stosuje się do wszystkich Variants, ale może być nadpisany w productFlavors i buildTypes. BuildConfigField dodany w buildType jest widoczny we wszystkich flavor tego typu, a dodany w productFlavor — we wszystkich typach tego flavor. Jeśli pole jest zdefiniowane zarówno tam, jak i tam — priorytet ma buildType (jest stosowany jako ostatni w łańcuchu).

Tabela porównawcza

CechaBuild TypeProduct Flavor
PrzeznaczenieJak kompilowaćCo kompilować
Przykładydebug, release, stagingfree, paid, demo, enterprise
Domyślniedebug + releasejeden (main)
Source Setsrc/debug/, src/release/src/free/, src/paid/
WymiarynieflavorDimensions
Zastosowaniepo flavor, nadpisujepo defaultConfig
BuildConfigFieldnadpisuje flavornadpisuje defaultConfig

Konfiguracja Build Variants w build.gradle

Priorytet konfiguracji

Konfiguracja Build Variants jest wykonywana w bloku android pliku build.gradle na poziomie modułu. Najpierw deklaruje się buildTypes z ich parametrami, następnie flavorDimensions i productFlavors. Gradle automatycznie tworzy warianty na podstawie tych deklaracji. Każdy wariant dziedziczy defaultConfig modułu, nadpisując określone pola. Kolejność deklaracji wpływa na priorytet: buildTypes są stosowane po productFlavors.

Aby uzyskać dostęp do konkretnego Build Variant w skryptach Gradle, używa się android.applicationVariants (dla modułu app) lub android.libraryVariants (dla modułu bibliotecznego). Jest to kolekcja, po której można iterować i zmieniać konfigurację każdego wariantu w czasie konfiguracji. Na przykład można programowo dodać buildConfigField dla wszystkich wariantów zawierających słowo „demo“.

Android Gradle Plugin 8.x dodał obsługę onVariants — czystszego API do konfiguracji wariantów przez lambdy. Stare API (variantOutput, variantFilter) jest oznaczone jako przestarzałe. Zaleca się używanie onVariants razem z onEach dla modułów bibliotecznych. Migracja z variantOutput na onVariants — zalecany krok przy aktualizacji AGP z 7.x na 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 i nadpisywanie zasobów

Każdy Build Variant otrzymuje własną hierarchię source sets — katalogów z kodem źródłowym, zasobami i manifestem. Source set lokalizuje się w src/<variantName>/ (np. src/freeDebug/) i może zawierać java/, res/, AndroidManifest.xml, assets/. Jeśli plik istnieje w source set wariantu, nadpisuje plik o tej samej nazwie z głównego source set (src/main/). Dla zasobów działa scalanie, a nie zastępowanie — system łączy zasoby ze wszystkich aktywnych source sets, dając priorytet specyficznym dla wariantu.

Source sets dla Build Variant są budowane w łańcuchu: src/main/src/flavor/src/type/src/flavorType/. Na przykład dla paidRelease najpierw stosuje się main, następnie paid, następnie release, następnie paidRelease. Każdy kolejny source set nadpisuje poprzedni. Oznacza to, że src/release/res/values/strings.xml nadpisze te same ciągi z src/paid/, ale src/paid/release/res/ jest jeszcze bardziej priorytetowy.

Używanie source sets dla wariantów — zalecany sposób dostosowywania zasobów. Zamiast sprawdzać BuildConfig.FLAVOR w kodzie i rozgałęziać logikę, można po prostu umieścić różne pliki w różnych source sets. Na przykład ikony dla wersji free i paid umieszcza się odpowiednio w src/free/res/ i src/paid/res/, a AndroidManifest z różnymi uprawnieniami — w src/free/AndroidManifest.xml i src/paid/AndroidManifest.xml. Jest to czystsze, szybsze (zasoby są kompilowane, a nie sprawdzane w czasie wykonania) i bezpieczniejsze (nie można przypadkowo włączyć płatnej funkcjonalności w darmowej wersji z powodu błędu w kodzie).

Build Variant w projektach wielomodułowych

W projektach wielomodułowych każdy moduł (biblioteka) może mieć własne Build Variants. AGP automatycznie synchronizuje warianty: jeśli moduł app kompiluje paidRelease, wszystkie zależne biblioteki również są kompilowane w ich wariantach odpowiadających paidRelease. Problem pojawia się, gdy biblioteka nie ma product flavors, ale moduł app ma — wtedy biblioteka jest kompilowana raz (release lub debug w zależności od typu).

Dla modułów bibliotecznych Build Variant domyślnie pokrywa się z Build Type modułu app, ponieważ biblioteki nie mają product flavors. Jeśli biblioteka ma dostosowywać się do flavor modułu app, należy zadeklarować te same flavorDimensions i productFlavors w bibliotece. AGP dopasowuje flavor po pełnej zgodności nazwy. Gradle zaleca synchronizowanie flavor przez konfigurację kompilacji w projekcie głównym za pomocą subprojects lub Convention Plugins.

Począwszy od AGP 8.1, biblioteki mogą publikować multiple variants — opublikować w repozytorium maven wszystkie warianty biblioteki jednocześnie. Rozwiązuje to problem, gdy moduł app używa paid flavor, a biblioteka jest opublikowana tylko dla free. Multiple variants publishing (MVP) umożliwia zależnemu projektowi automatyczne wybranie potrzebnego wariantu. Aby włączyć MVP, należy dodać publishing { multipleVariants { ... } } w build.gradle biblioteki.

Filtrowanie i wyłączanie wariantów

Dynamiczne filtrowanie przez CI/CD

Czasami konieczne jest wyłączenie części Build Variants — na przykład jeśli kombinacja mockRelease nie ma sensu (serwer mock nie powinien trafić do produkcji). Gradle udostępnia variantFilter — blok DSL, w którym można sprawdzać właściwości każdego wariantu i wyłączać go przez setIgnore(true). VariantFilter jest stosowany na etapie konfiguracji, przed utworzeniem zadań, więc wyłączony wariant nie generuje zadań assemble i install.

Filtrowanie jest również przydatne do przyspieszenia kompilacji. Jeśli w projekcie jest 8 wariantów, a programista pracuje tylko nad jednym, pozostałe 7 wariantów i tak przechodzą konfigurację (configuration phase). Przy użyciu variantFilter wyłączone warianty nie tworzą zadań, co skraca czas konfiguracji o 30-50% dla projektów z 6+ wymiarami flavor. W CI/CD można dynamicznie filtrować warianty przez parametry wiersza poleceń -PbuildOnly=paidRelease.

groovy
android {
    variantFilter { variant ->
        // Wyłącz mock dla release i demo dla produkcji
        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)
        }
    }
}

// Dynamiczne filtrowanie przez parametry
if (project.hasProperty("buildOnly")) {
    def target = project.property("buildOnly")
    android.variantFilter { variant ->
        variant.setIgnore(variant.name != target)
    }
}

Często zadawane pytania

Ile Build Variants można utworzyć?

Nie ma ograniczeń, ale Gradle tworzy iloczyn kartezjański wszystkich flavor i typów. Jeśli masz 3 wymiary po 3 flavor i 3 build type — otrzymasz 27 wariantów. Zbyt wiele wariantów spowalnia konfigurację. Zaleca się nie więcej niż 10-12 wariantów w jednym module.

Po co są potrzebne flavorDimensions?

flavorDimensions grupują Product Flavors w niezależne osie. Na przykład wymiar „tier“ (free, paid) i „region“ (us, eu). Bez wymiarów wszystkie flavor należą do jednej osi i Gradle będzie wybierał tylko jeden flavor ze wszystkich (nie można mieć free+us i paid+eu jako oddzielnych wariantów).

Jak nadpisać applicationId dla wariantu?

W bloku productFlavor lub buildType wskaż applicationId. Na przykład dla wersji free: free { applicationId "com.example.app.free" }. W manifeście użyj ${applicationId} — Gradle automatycznie podstawi wartość. Pozwala to zainstalować oba warianty na jednym urządzeniu.

Czy można używać Build Variants w iOS?

W iOS odpowiednikiem Build Variants jest kombinacja Scheme + Configuration. Xcode Schemes są konfigurowane przez konfiguracje Debug/Release z różnymi parametrami. Dla wielu wersji (free/paid) używa się Build Configurations i Preprocessor Macros. W Androidzie koncepcja jest sformalizowana bardziej rygorystycznie i wbudowana w Gradle.

Czy Build Variant wpływa na rozmiar APK?

Tak, każdy wariant może mieć inny rozmiar APK. Kompilacje debug zawierają informacje debugowania, SDK i nieobsługiwane zasoby. Kompilacje release z minifikacją i zmniejszaniem zasobów dają minimalny rozmiar. Product Flavor również wpływa: wersja free bez płatnych bibliotek będzie mniejsza od wersji paid o rozmiar tych bibliotek.

Podsumowanie

  • Build Variant — kombinacja jednego Build Type i jednego Product Flavor, określająca konfigurację kompilacji.
  • Build Type zarządza trybem kompilacji (debug/release/staging), a Product Flavor — wersją produktu (free/paid).
  • Source sets umożliwiają nadpisywanie kodu, zasobów i manifestu dla każdego wariantu kompilacji.
  • VariantFilter wyłącza niepotrzebne kombinacje, przyspieszając konfigurację Gradle o 30-50%.
  • Projekty wielomodułowe wymagają synchronizacji flavor przez wszystkie moduły lub multiple variants publishing.
  • BuildConfigField i source sets — dwa czyste sposoby dostosowywania zachowania między wariantami.
  • Zalecenie: nie twórz więcej niż 10-12 wariantów w jednym projekcie, grupuj wymiary w przemyślany sposób.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również