Product Flavor: Was es ist, Konfiguration und Beispiele in Gradle

Autor: IT Sectr Veröffentlicht: 2026-05-30 Lesezeit: 9 Min.

Product Flavor in der Android-Entwicklung ist ein Gradle-Mechanismus, der es ermöglicht, mehrere Varianten derselben Anwendung aus einer gemeinsamen Codebasis zu erstellen. Jeder Flavor kann seine eigene applicationId, Ressourcen, Abhängigkeiten und Funktionalität haben — zum Beispiel kostenlose und kostenpflichtige Versionen. Laut Google Android Developers, 2025 sind Product Flavors Teil des Build Variants-Systems und werden über flavorDimensions mit Build Types kombiniert. Dies ist der Standardansatz für die Veröffentlichung mehrerer App-Versionen bei Google Play.

Wichtige Punkte

  • Product Flavor — eine Produktvariante mit eindeutiger applicationId, Ressourcen und Code.
  • Flavor Dimensions gruppieren Flavors in unabhängige Achsen für mehrdimensionale Konfiguration.
  • Source Sets für einen Flavor überschreiben Hauptressourcen: Icons, Zeichenketten, Manifest.
  • Gradle generiert automatisch einen Build Variant für jede Kombination aus Flavor + Build Type.
  • Google Play unterstützt die Veröffentlichung mehrerer Flavors als separate Apps oder einer einzelnen App mit verschiedenen Konfigurationen.

Was ist Product Flavor?

Product Flavor ist eine Gradle-Konfiguration im Block android.productFlavors, die eine Produktvariante beschreibt. Jeder Flavor kann applicationId, versionName, versionCode, minSdkVersion, targetSdkVersion, signingConfig und andere Parameter von defaultConfig überschreiben. Product Flavors haben keine Mengenbegrenzung: Ein Projekt kann 2, 5 oder 10 Flavors enthalten — Gradle verarbeitet alle Kombinationen.

Product Flavor löst das Problem der Codebasis-Wiederverwendung (codebase reuse) — wenn aus einem einzigen Repository mehrere verschiedene Anwendungen erstellt werden müssen. Typische Szenarien: eine kostenlose Version mit Werbung und eine kostenpflichtige ohne; eine Demoversion mit eingeschränkter Funktionalität; Unternehmens- und Verbraucherversionen; White-Label-Apps für verschiedene Kunden. Ohne Product Flavors müsste jede Version in einem separaten Projekt verwaltet werden, was zu 60-70% Code-Duplikation führt.

Historisch gesehen erschienen Product Flavors in Android Gradle Plugin 0.9 (2013) als Ersatz für Ant-Konfigurationen. Zuvor verwendeten Entwickler separate Projekte für verschiedene Versionen oder manuellen Ressourcenaustausch vor dem Build. Die Einführung von Flavors in AGP vereinheitlichte den Ansatz und machte ihn zum Standard. Laut einer Umfrage von JetBrains, 2024 verwenden 78% der Android-Projekte mit mehreren Versionen Product Flavors, der Rest verwendet manuelles Umschalten über BuildConfig oder Reflection.

Product Flavor vs. Build Type

Build Type verwaltet den Build-Prozess (Debug mit Debugging, Release mit Optimierung). Product Flavor verwaltet den Build-Inhalt (free ohne kostenpflichtige Funktionen, paid mit ihnen). Build Type ist eine Infrastruktureinstellung, Product Flavor ist eine Produkteinstellung. Beide Konzepte sind orthogonal: Ein Debug-Build des Free-Flavors unterscheidet sich von einem Release-Build des Free-Flavors nur in den Kompilierungsparametern, nicht in der Funktionalität. Product Flavor kann nicht zum Deaktivieren des Debuggers verwendet werden — das ist die Aufgabe von Build Type.

Flavor Dimensions: Organisation von Dimensionen

Reihenfolge der Dimensionen und Priorität

Flavor Dimensions sind ein Gruppierungsmechanismus für Product Flavors in unabhängige Kategorien. Wenn eine App eine kostenlose/kostenpflichtige Version und separat eine amerikanische/europäische Region hat, werden Flavors in zwei Dimensionen gruppiert: "tier" (free, paid) und "region" (us, eu). Gradle erstellt das kartesische Produkt der Dimensionen: freeUs, freeEu, paidUs, paidEu — 4 Varianten. Ohne Dimensionen würde Gradle alle vier Flavors als eine einzige Ebene behandeln, und nur einer könnte ausgewählt werden.

Dimensionen werden im Block flavorDimensions als Zeichenkette oder Liste von Zeichenketten deklariert. Die Reihenfolge der Dimensionen beeinflusst die Priorität der Source Sets: Die erste Dimension hat die höchste Priorität. Wenn Dimension A (tier) zuerst angegeben wird, überschreibt src/free/ im Falle von Ressourcenkonflikten src/us/. Die Reihenfolge beeinflusst auch, wie der Variantenname gebildet wird: Zuerst kommen die Flavors der ersten Dimension, dann der zweiten, dann Build Type: freeUsDebug.

Die Anzahl der Dimensionen ist nicht begrenzt, aber jede neue Dimension multipliziert die Anzahl der Build Variants. Für ein Projekt mit 4 Dimensionen (je 2 Flavors) und 2 Build Types erhält man 2 × 2 × 2 × 2 × 2 = 32 Varianten. Die praktische Grenze liegt bei 3 Dimensionen (maximal 8-12 Varianten). Darüber hinaus verlangsamt sich die Gradle-Konfiguration und das Build Variants-Panel in Android Studio wird unlesbar.

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
        }
    }
}

// Ergebnis: freeMinApi21, freeMinApi26, paidMinApi21, paidMinApi26
// Jede × debug/release = 8 Build Variants

Erstellung von Product Flavors in build.gradle

Kotlin DSL für Product Flavors

Um einen Product Flavor zu erstellen, muss ein Block productFlavors innerhalb von android hinzugefügt werden, der den Flavor-Namen und seine Parameter angibt. Die minimale Flavor-Deklaration ist der Name und die Dimension. Alle anderen Parameter werden von defaultConfig geerbt und können überschrieben werden. Der Flavor erbt defaultConfig vollständig, einschließlich applicationId, versionCode, testInstrumentationRunner.

Jeder Flavor kann applicationId überschreiben — dies ermöglicht die gleichzeitige Installation mehrerer App-Versionen auf demselben Gerät. Zum Beispiel wird die kostenlose Version com.example.app.free sein, die kostenpflichtige — com.example.app.paid. Wenn applicationId nicht überschrieben wird, haben alle Flavors dieselbe Kennung und können nicht nebeneinander installiert werden. applicationId muss mit dem Paket im Manifest übereinstimmen (sofern nicht applicationIdSuffix verwendet wird).

AGP 8+ empfiehlt die Verwendung von Kotlin DSL anstelle von Groovy für build.gradle. Kotlin DSL bietet typsicheren Zugriff auf die Konfiguration: Die IDE schlägt Parameternamen vor, überprüft Typen zur Kompilierzeit und hebt Fehler hervor. Die Migration von Groovy zu Kotlin DSL für Product Flavors besteht in der Regel aus dem Ersetzen von Anführungszeichen durch Klammern und dem Hinzufügen von Typen. AGP ist abwärtskompatibel — beide Syntaxen funktionieren parallel im selben Projekt.

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")
        }
    }
}

Ressourcen und Code für verschiedene Flavors

Jeder Product Flavor erstellt sein eigenes Source Set — ein Verzeichnis src/<flavorName>/. Dieses Verzeichnis kann überschriebene Ressourcen, Quelldateien und das Manifest enthalten. Das Flavor-Source Set fungiert als Overlay über main: Dateien aus src/free/res/ überschreiben Dateien aus src/main/res/ mit denselben Namen. Dies ermöglicht unterschiedliche Zeichenketten, Icons, Farben und Layouts für jeden Flavor, ohne den Hauptcode zu ändern.

Zum Überschreiben von Java/Kotlin-Klassen gibt es zwei Ansätze: Flavor-spezifische Implementierung (Implementierung einer abstrakten Klasse in jedem Flavor) und BuildConfig-Feld (Verzweigung im Code). Der erste Ansatz ist sauberer: Sie definieren ein Interface oder eine abstrakte Klasse in main und konkrete Implementierungen in src/free/ und src/paid/. Während des Builds wird nur die Implementierung des aktuellen Flavors kompiliert. Dies bietet gleichzeitige Vorteile: kleinere APK-Größe (kostenpflichtiger Code gelangt nicht in die kostenlose Version) und Sicherheit (es ist unmöglich, versehentlich eine kostenpflichtige Funktion aufzurufen).

AndroidManifest.xml in einem Flavor-Source Set ersetzt nicht, sondern wird mit dem Hauptmanifest zusammengeführt. Die Zusammenführung folgt den Android-Regeln: Doppelte Attribute im selben Element werden überschrieben, eindeutige werden hinzugefügt. Wenn beispielsweise das Hauptmanifest die INTERNET-Berechtigung deklariert und free nicht, bleibt die Internet-Berechtigung erhalten. tools:node="replace" ermöglicht jedoch das Ersetzen eines gesamten Manifest-Blocks für einen bestimmten Flavor. Dies ist nützlich, wenn verschiedene Flavors unterschiedliche Berechtigungen benötigen (SD-Karte-Schreiben für paid, Kamera für free).

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>

Beispiel: Kostenlose und kostenpflichtige App-Versionen

Betrachten wir ein typisches Szenario: free — eine Version mit Werbung und Basisfunktionen, paid — ohne Werbung, mit erweiterter Funktionalität. Für die kostenlose Version wird applicationId auf "com.example.app.free" gesetzt, für die kostenpflichtige — auf "com.example.app.paid". Beide Versionen können gleichzeitig auf demselben Gerät installiert werden, da applicationId der eindeutige Anwendungsbezeichner im Android-System ist.

Architektonisch wird die Trennung durch Interface + Flavor-Implementierung aufgebaut. Im Haupt-Source Set wird das Interface PaymentService deklariert. In src/free/ befindet sich eine Implementierung, die vor der Zahlung über AdMob eine Werbung anzeigt. In src/paid/ — eine Implementierung, die direkt zum Zahlungsgateway weiterleitet. Code, der PaymentService verwendet, weiß nicht, welche Implementierung geladen ist — dies wird zur Kompilierzeit entschieden. Dieser Ansatz garantiert, dass Abonnementverwaltungscode nicht in die kostenlose Version gelangt, selbst wenn der Entwickler ihn versehentlich aufruft.

Die APK-Größe für verschiedene Flavors kann aufgrund des Ein-/Ausschlusses von Abhängigkeiten um 5-15 MB abweichen. Um eine Bibliothek aus einem bestimmten Flavor auszuschließen, verwenden Sie Flavor-spezifische Abhängigkeiten in build.gradle: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Diese Abhängigkeit wird nur für die freie Variante hinzugefügt und vergrößert die kostenpflichtige Version nicht. Für gemeinsame Abhängigkeiten verwenden Sie implementation — alle Flavors schließen sie ein.

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 in Multimodul-Projekten

In Multimodul-Projekten haben Bibliotheksmodule möglicherweise keine eigenen Product Flavors, was ein Problem verursacht: Die Bibliothek wird einmal (als Release) erstellt, während das App-Modul mit Flavor die Bibliothek mit der entsprechenden Variante erwartet. Ab AGP 8.1 können Bibliotheken mehrere Varianten über den Block publishing.multipleVariants veröffentlichen — dies ermöglicht die Veröffentlichung aller Flavor-Varianten der Bibliothek in einem einzigen Maven-Repository, und das App-Modul wählt automatisch die richtige aus.

Ein alternativer Ansatz besteht darin, dieselben flavorDimensions und productFlavors in der Bibliothek wie im App-Modul zu deklarieren. AGP gleicht Flavors automatisch durch exakte Namensübereinstimmung innerhalb einer Dimension ab. Wenn der Flavor-Name in der Bibliothek mit dem Namen in der App übereinstimmt, erstellt AGP konsistente Varianten. Zur einfacheren Wartung wird empfohlen, gemeinsame Flavor-Definitionen in ein Convention Plugin auszulagern — ein Gradle-Plugin, das auf alle Module des Projekts angewendet wird.

Für Bibliotheken, die nicht zur Veröffentlichung bestimmt sind (interne Module), reicht es aus, die Flavors über die build.gradle des Root-Projekts zu synchronisieren. Gradle bietet die Methode subprojects, mit der Konfiguration auf alle Unterprojekte angewendet werden kann. Beachten Sie jedoch, dass zu viel Konfiguration in subprojects die Konfigurationsphase verlangsamt. Es wird empfohlen, Convention Plugins zu verwenden — sie werden einmal kompiliert und wiederverwendet, was die Konfigurationszeit um 15-30% reduziert.

Häufig gestellte Fragen

Wie viele Product Flavors können erstellt werden?

Es gibt keine Mengenbegrenzung, aber jede Dimension multipliziert die Anzahl der Build Variants. 4 Flavors in einer Dimension + 2 Build Types = 8 Varianten. 4 + 4 in zwei Dimensionen = 16 Varianten. Es wird empfohlen, nicht mehr als 3 Dimensionen und insgesamt 10-12 Varianten zu verwenden.

Kann das Manifest für einen Flavor überschrieben werden?

Ja, über das Source Set src/<flavor>/AndroidManifest.xml. Das Manifest wird mit dem Hauptmanifest zusammengeführt. Zum Ersetzen eines gesamten Blocks verwenden Sie tools:node="replace". Ersetzen Sie beispielsweise das App-Label oder die Berechtigungen für einen bestimmten Flavor.

Wie fügt man Flavor-spezifische Abhängigkeiten hinzu?

Verwenden Sie die Konfiguration <flavorName>Implementation. Beispiel: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Diese Abhängigkeit wird nur beim Erstellen der freien Variante eingeschlossen. Für die kostenpflichtige: paidImplementation. Gemeinsame Abhängigkeiten werden über implementation angegeben.

Worin unterscheidet sich Product Flavor von Build Type?

Product Flavor definiert die Produktversion (free, paid, demo), Build Type definiert die Build-Methode (debug, release). Flavors können applicationId, versionName, Ressourcen überschreiben. Build Type steuert debuggable, Minification, Signing. Beide sind orthogonal und kombinieren sich zu Build Variant.

Kann Product Flavor mit Jetpack Compose verwendet werden?

Ja, Product Flavors funktionieren ohne Einschränkungen mit Compose. Verschiedene Flavors können über Source Sets oder abstrakte Klassenimplementierungen unterschiedliche Compose-Bildschirme haben. Sie können auch Flavor-spezifische Compose-Abhängigkeiten hinzufügen: freeImplementation 'androidx.compose.ui:ui-tooling'.

Zusammenfassung

  • Product Flavor — ein Gradle-Mechanismus zum Erstellen mehrerer App-Versionen aus einer einzigen Codebasis.
  • Flavor Dimensions gruppieren Flavors in Dimensionen und ermöglichen die Kombination verschiedener Aspekte der App.
  • Source Sets für einen Flavor überschreiben Ressourcen, Code und das Manifest, ohne das Hauptverzeichnis zu ändern.
  • Interface + Flavor-Implementierung ist ein sauberer architektonischer Ansatz zur Trennung von Funktionalitäten.
  • Flavor-spezifische Abhängigkeiten verhindern, dass unnötige Bibliotheken in ungeeignete Versionen gelangen.
  • Multimodul-Projekte erfordern eine Flavor-Synchronisierung über Convention Plugins oder die Veröffentlichung mehrerer Varianten.
  • Empfehlung: nicht mehr als 3 Flavor-Dimensionen und nicht mehr als 10 Build Variants insgesamt in einem Projekt.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch