Product Flavor: mi ez, konfiguráció és példák Gradle-ben

Szerző: IT Sectr Megjelenés: 2026-05-30 Olvasási idő: 9 perc

A Product Flavor az Android-fejlesztésben egy Gradle-mechanizmus, amely lehetővé teszi több változat létrehozását egy alkalmazásból egy közös kódbázisból. Minden flavor rendelkezhet saját applicationId-val, erőforrásokkal, függőségekkel és funkcionalitással — például ingyenes és fizetős változattal. A Google Android Developers, 2025 szerint a Product Flavors a Build Variants rendszer része és a Build Types-szal kombinálódik a flavorDimensions segítségével. Ez a standard megközelítés egy alkalmazás több változatának közzétételére a Google Play-ben.

FŐbb PONTOK

  • Product Flavor — termékváltozat egyedi applicationId-val, erőforrásokkal és kóddal.
  • Flavor Dimensions a flavor-okat független tengelyekbe csoportosítják többdimenziós konfigurációhoz.
  • Source sets a flavor számára felülírják a main erőforrásokat: ikonokat, szövegeket, manifestet.
  • Gradle automatikusan generál Build Variant-ot minden flavor + build type kombinációhoz.
  • Google Play támogatja több flavor közzétételét különálló alkalmazásként vagy egyként különböző konfigurációkkal.

Mi az a Product Flavor?

Product Flavor egy Gradle-konfiguráció az android.productFlavors blokkban, amely egy termékváltozatot ír le. Minden flavor felülírhatja az applicationId-t, versionName-t, versionCode-ot, minSdkVersion-t, targetSdkVersion-t, signingConfig-ot és egyéb defaultConfig paramétereket. A Product Flavors-nak nincs mennyiségi korlátozása: egy projekt tartalmazhat 2, 5, 10 flavor-t — a Gradle feldolgozza az összes kombinációt.

A Product Flavor megoldja a codebase reuse problémát — amikor egyetlen tárolóból több különböző alkalmazást kell építeni. Tipikus forgatókönyvek: ingyenes verzió hirdetésekkel és fizetős anélkül; demo verzió korlátozott funkcionalitással; vállalati és fogyasztói verziók; white-label alkalmazások különböző ügyfelek számára. Product Flavors nélkül minden verziót külön projektben kellene fenntartani, ami a kód 60-70%-os duplikálódásához vezet.

Történetileg a Product Flavors az Android Gradle Plugin 0.9-ben (2013) jelent meg az ant konfigurációk helyettesítéseként. Előtte a fejlesztők külön projekteket használtak különböző verziókhoz vagy kézi erőforrás-cserét a fordítás előtt. A flavor-ok AGP-be történő bevezetése egységesítette a megközelítést és szabvánnyá tette. A JetBrains, 2024 felmérése szerint a több verziós Android projektek 78%-a használ Product Flavors-t, a többi — kézi váltást BuildConfig-on vagy reflectionön keresztül.

Product Flavor vs Build Type

Build Type a fordítási folyamatot kezeli (debug hibakereséssel, release optimalizálással). Product Flavor a fordítás tartalmát kezeli (free fizetős funkciók nélkül, paid azokkal). A Build Type infrastrukturális konfiguráció, a Product Flavor — termékkonfiguráció. Mindkét fogalom ortogonális: a free-flavor debug fordítása csak a fordítási paraméterekben különbözik a free-flavor release fordításától, nem a funkcionalitásban. A Product Flavor nem használható a hibakereső kikapcsolására — ez a Build Type feladata.

Flavor Dimensions: dimenziók szervezése

A dimenziók sorrendje és prioritása

Flavor Dimensions (dimenziók) — a Product Flavors független kategóriákba csoportosításának mechanizmusa. Ha egy alkalmazásnak van ingyenes/fizetős verziója és külön amerikai/európai régiója, a flavour-ok két dimenzióba csoportosulnak: „tier” (free, paid) és „region” (us, eu). A Gradle létrehozza a dimenziók Descartes-szorzatát: freeUs, freeEu, paidUs, paidEu — 4 variáns. Dimenziók nélkül a Gradle mind a négy flavour-t egy síkként érzékelné, és csak egy választható ki.

A dimenziók a flavorDimensions blokkban kerülnek deklarálásra szövegként vagy szövegek listájaként. A dimenziók sorrendje befolyásolja a source sets prioritását: az első dimenziónak van a legmagasabb prioritása. Ha az A dimenzió (tier) az első, akkor src/free/ felülírja a src/us/-t erőforrás ütközés esetén. A sorrend a Variant elnevezését is befolyásolja: először az első dimenzió flavour-ja, aztán a másodiké, majd a Build Type: freeUsDebug.

A dimenziók száma nem korlátozott, de minden új dimenzió megsokszorozza a Build Variants számát. Egy 4 dimenziós (mindegyikben 2 flavour) és 2 build types projekt esetén: 2 × 2 × 2 × 2 × 2 = 32 variáns. Gyakorlati határ — 3 dimenzió (maximum 8-12 variáns). Több — és a Gradle konfiguráció lelassul, és az Android Studio Build Variants panelje olvashatatlanná válik.

groovy
android {
    flavorDimensions "tier", "api"

    productFlavors {
        free {
            dimension "tier"
            applicationId "com.example.app.free"
            versionNameSuffix "-free"
        }
        paid {
            dimension "tier"
            applicationId "com.example.app.paid"
        }
        minApi21 {
            dimension "api"
            minSdk 21
        }
        minApi26 {
            dimension "api"
            minSdk 26
        }
    }
}

// Eredmény: freeMinApi21, freeMinApi26, paidMinApi21, paidMinApi26
// Mindegyik × debug/release = 8 Build Variants

Product Flavors létrehozása build.gradle-ben

Kotlin DSL Product Flavors-hoz

Egy Product Flavor létrehozásához hozzá kell adni a productFlavors blokkot az androidon belül, megadva a flavor nevét és paramétereit. A flavor minimális deklarációja a név és a dimension. Az összes többi paraméter a defaultConfig-ból örlödik és felülírható. A Flavor teljes mértékben örökli a defaultConfig-ot, beleértve az applicationId-t, versionCode-ot és testInstrumentationRunner-t.

Minden flavor felülírhatja az applicationId-t — ez lehetővé teszi több alkalmazásváltozat egyidejű telepítését egyetlen eszközre. Például a free verzió com.example.app.free lesz, a paid pedig com.example.app.paid. Ha az applicationId nincs felülírva, az összes flavour azonos azonosítóval rendelkezik, és nem telepíthetők párhuzamosan. Az applicationId-nak meg kell egyeznie a manifestben lévő package-tel (ha nem használnak applicationIdSuffix-et).

Az AGP 8+ a Groovy helyett a Kotlin DSL használatát ajánlja a build.gradle számára. A Kotlin DSL típusbiztos hozzáférést biztosít a konfigurációhoz: az IDE javasolja a paraméterneveket, ellenőrzi a típusokat fordítási időben és kiemeli a hibákat. A Groovy-ról Kotlin DSL-re való áttérés a Product Flavors esetén általában az idézőjelek zárójelekkel történő helyettesítéséből és típusok hozzáadásából áll. Az AGP visszafelé kompatibilis — mindkét szintaxis párhuzamosan működik ugyanabban a projektben.

kotlin
// build.gradle.kts — Kotlin DSL
android {
    flavorDimensions += "tier"

    productFlavors {
        register("free") {
            dimension = "tier"
            applicationId = "com.example.app.free"
            versionNameSuffix = "-free"
            buildConfigField("boolean", "IS_PREMIUM", "false")
        }
        register("paid") {
            dimension = "tier"
            applicationId = "com.example.app.paid"
            versionNameSuffix = "-paid"
            buildConfigField("boolean", "IS_PREMIUM", "true")
        }
    }
}

Erőforrások és kód különböző flavor-okhoz

Minden Product Flavor létrehozza a saját source set-jét — a src/<flavorName>/ könyvtárat. Ebben a könyvtárban helyezhetők el a felülírt erőforrások, forráskód és manifest. A flavor source set rétegként működik a main felett: a src/free/res/ fájljai felülírják az azonos nevű src/main/res/ fájlokat. Ez lehetővé teszi különböző szövegek, ikonok, színek és elrendezések használatát minden flavor számára anélkül, hogy a fő kódot módosítanánk.

A Java/Kotlin osztályok felülírására két megközelítés létezik: flavor-specific implementation (absztrakt osztály implementálása minden flavor-ban) és BuildConfig field (elágazás a kódban). Az első megközelítés tisztább: definiálsz egy interfészt vagy absztrakt osztályt a main-ben, és konkrét implementációkat a src/free/ és src/paid/ könyvtárakban. Fordításkor csak az aktuális flavor implementációja fordul. Ez egyidejű előnyöket biztosít: kisebb APK méret (a fizetős kód nem kerül a free verzióba) és biztonság (a fizetős funkció véletlenül sem hívható meg).

AndroidManifest.xml a flavor source set-ben nem helyettesíti, hanem összeolvad a main manifesttel. Az összeolvadás az Android szabályai szerint történik: ugyanazok az attribútumok egy elemben felülíródnak, az egyediek hozzáadódnak. Például, ha a main manifestben deklarálva van az INTERNET engedély, a free-ben pedig nem, az internet megmarad. De a tools:node="replace" lehetővé teszi a manifest teljes blokkjának cseréjét egy adott flavor számára. Ez akkor hasznos, ha különböző flavour-ok különböző engedélyeket igényelnek (írás SD-re a paid számára, kamera a free számára).

xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:label="Free App"
        tools:replace="android:label">
    </application>
</manifest>

Példa: az alkalmazás ingyenes és fizetős változata

Tekintsünk egy tipikus forgatókönyvet: free — verzió hirdetésekkel és alapfunkciókkal, paid — hirdetések nélkül, kiterjesztett funkcionalitással. A free verzióhoz az applicationId „com.example.app.free” van beállítva, a paid-hoz — „com.example.app.paid”. Mindkét verzió telepíthető ugyanarra az eszközre egyidejűleg, mivel az applicationId az alkalmazás egyedi azonosítója az Android rendszerben.

Architekturálisan a szétválasztás az interface + flavor implementation elven alapul. A main source set-ben deklarálásra kerül a PaymentService interfész. A src/free/ könyvtárban található az implementáció, amely AdMob-on keresztül hirdetéseket jelenít meg fizetés előtt. A src/paid/ könyvtárban — az implementáció, amely közvetlenül a fizetési átjáróhoz lép. A PaymentService-t használó kód nem tudja, melyik implementáció van betöltve — ez fordítási időben dől el. Ez a megközelítés garantálja, hogy az előfizetés-kezelő kód nem kerül a free verzióba, még akkor sem, ha a fejlesztő véletlenül meghívja.

Az APK mérete különböző flavor-ok esetén 5-15 MB-tal térhet el a függőségek be-/kizárása miatt. Egy könyvtár kizárásához egy adott flavor-ból a flavor-specific dependencies használandó a build.gradle-ben: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Ez a függőség csak a free variánshoz kerül hozzáadásra, és nem növeli a paid verzió méretét. A közös függőségekhez az implementation használandó — ezek minden flavor-ban benne vannak.

kotlin
// src/main/kotlin/com/example/payment/PaymentService.kt
interface PaymentService {
    fun processOrder(amount: Double, callback: (PaymentResult) -> Unit)
}

// src/free/kotlin/.../FreePaymentService.kt
class FreePaymentService : PaymentService {
    override fun processOrder(amount: Double, callback: (PaymentResult) -> Unit) {
        AdManager.showInterstitial {
            PaymentGateway.charge(amount, callback)
        }
    }
}

// src/paid/kotlin/.../PaidPaymentService.kt
class PaidPaymentService : PaymentService {
    override fun processOrder(amount: Double, callback: (PaymentResult) -> Unit) {
        PaymentGateway.charge(amount, callback)
    }
}

Product Flavor többmodulos projektekben

Többmodulos projektekben a könyvtármoduloknak nem biztos, hogy saját Product Flavors-uk van, ami problémát okoz: a könyvtár egyszer fordul (release-ként), de a flavor-ral rendelkező app modul a könyvtár megfelelő variánsát várja. AGP 8.1-től kezdve a könyvtárak multiple variants közzétételére képesek a publishing.multipleVariants blokk segítségével — ez lehetővé teszi a könyvtár összes flavor variánsának közzétételét egyetlen maven tárolóba, és az app modul automatikusan kiválasztja a szükségest.

Alternatív megközelítés — ugyanazon flavorDimensions és productFlavors deklarálása a könyvtárban, mint az app modulban. Az AGP automatikusan párosítja a flavour-okat a név teljes egyezése alapján egy dimenzióban. Ha a flavor neve a könyvtárban megegyezik az app-beli névvel, az AGP konzisztens variánsokat hoz létre. A karbantarthatóság érdekében ajánlott a közös flavour-definíciókat egy Convention Plugin-ba — egy Gradle pluginba, amely a projekt összes moduljára alkalmazandó — helyezni.

A nem közzétételre szánt könyvtárak (belső modulok) esetében elegendő a flavour-ok szinkronizálása a gyökérprojekt build.gradle-jén keresztül. A Gradle biztosítja a subprojects metódust, amely lehetővé teszi a konfiguráció alkalmazását az összes alprojektre. Azonban ne feledje, hogy a túl nagy konfiguráció a subprojects-ben lelassítja a konfigurációs fázist. A Convention Plugins használata ajánlott — ezek egyszer fordulnak és újrafelhasználhatóak, ami 15-30%-kal csökkenti a konfigurációs időt.

Gyakran Ismételt Kérdések

Hány Product Flavor hozható létre?

Nincs számbeli korlátozás, de minden dimenzió megsokszorozza a Build Variants számát. 4 flavour egy dimenzióban + 2 build types = 8 variáns. 4 + 4 két dimenzióban = 16 variáns. Legfeljebb 3 dimenzió és 10-12 összes variáns ajánlott.

Felülírható a manifest egy flavour számára?

Igen, a src/<flavor>/AndroidManifest.xml source set-en keresztül. A manifest összeolvad a fő manifesttel. Egy teljes blokk cseréjéhez használja a tools:node="replace"-et. Például az alkalmazás címkéjének vagy engedélyeinek módosításához egy adott flavor számára.

Hogyan adhatok hozzá flavour-specifikus függőségeket?

Használja a <flavorName>Implementation konfigurációt. Példa: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Ez a függőség csak a free variáns fordításakor kerül bele. A paid esetében: paidImplementation. A közös függőségeket implementation-en keresztül kell megadni.

Miben különbözik a Product Flavor a Build Type-tól?

A Product Flavor a termékverziót (free, paid, demo) határozza meg, a Build Type — a fordítási módszert (debug, release). A Flavour-ok felülírhatják az applicationId-t, versionName-t és erőforrásokat. A Build Type a debuggable, minification és signing kezeléséért felel. Mindkettő ortogonális és a Build Variant-ban kombinálódik.

Használható a Product Flavor Jetpack Compose-szal?

Igen, a Product Flavors korlátozás nélkül működik a Compose-szal. A különböző flavor-ok eltérő Compose képernyőkkel rendelkezhetnek source sets-en vagy absztrakt osztályok implementálásán keresztül. Flavor-specifikus Compose függőségek is hozzáadhatók: freeImplementation 'androidx.compose.ui:ui-tooling'.

Összefoglalás

  • Product Flavor — Gradle-mechanizmus több alkalmazásváltozat létrehozására egy kódból.
  • Flavor Dimensions a flavor-okat dimenziókba csoportosítják, lehetővé téve az alkalmazás különböző aspektusainak kombinálását.
  • Source sets a flavor számára felülírják az erőforrásokat, kódot és manifestet a fő könyvtár módosítása nélkül.
  • Interface + flavor implementation — tiszta architekturális megközelítés a funkcionalitás szétválasztására.
  • Flavor-specifikus függőségek megakadályozzák a felesleges könyvtárak bekerülését a nem megfelelő verziókba.
  • Többmodulos projektek a flavour-ok szinkronizálását igénylik Convention Plugins vagy multiple variants publishing segítségével.
  • Ajánlás: legfeljebb 3 flavor dimenzió és legfeljebb 10 összes Build Variants a projektben.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is