Auf dieser Seite erfahren Sie, wie Sie Build-Varianten konfigurieren, um verschiedene Versionen Ihrer Anwendung aus einem einzigen Projekt zu erstellen, und wie Sie Ihre Abhängigkeiten und Signaturkonfigurationen ordnungsgemäß verwalten.
Jede Build-Variante steht für eine andere Version Ihrer App, die Sie erstellen können. Beispielsweise könntest du eine Version deiner App erstellen, die mit einer begrenzten Anzahl von Inhalten kostenlos ist, und eine andere kostenpflichtige Version, die mehr enthält. Du kannst auch verschiedene Versionen deiner App erstellen, die auf dem API-Level oder anderen Gerätevarianten für unterschiedliche Geräte ausgerichtet sind.
Build-Varianten basieren darauf, dass Gradle Einstellungen, Code und Ressourcen, die in Ihren Build-Typen und Produkt-Geschmacks konfiguriert sind, anhand bestimmter Regeln kombiniert. Obwohl Sie Build-Varianten nicht direkt konfigurieren, konfigurieren Sie die Build-Typen und Produkt-Varianten, aus denen sie bestehen.
Beispielsweise können in einem Demo-Produkt-Flavor bestimmte Funktionen und Geräteanforderungen festgelegt werden, z. B. benutzerdefinierter Quellcode, Ressourcen und Mindest-API-Levels. Mit dem Build-Typ "Debug" werden andere Build- und Paketeinstellungen angewendet, z. B. Fehlerbehebungsoptionen und Signaturschlüssel. Die Build-Variante, die diese beiden Komponenten kombiniert, ist die Version „demoDebug“ Ihrer Anwendung. Sie enthält eine Kombination aus den Konfigurationen und Ressourcen, die im Produkt-Flavor „Demo“, dem Build-Typ „Debug“ und dem Quellsatz main/
enthalten sind.
Build-Typen konfigurieren
Sie können Build-Typen im Block android
der Datei build.gradle.kts
auf Modulebene erstellen und konfigurieren. Wenn Sie ein neues Modul erstellen, erstellt Android Studio automatisch die Debug- und Release-Build-Typen. Obwohl der Debug-Build-Typ nicht in der Build-Konfigurationsdatei angezeigt wird, wird er in Android Studio mit debuggable
true
konfiguriert. So kannst du Fehler in der App auf sicheren Android-Geräten beheben und die App-Signatur mit einem generischen Keystore für die Fehlerbehebung konfigurieren.
Sie können den Debug-Build-Typ in Ihre Konfiguration aufnehmen, wenn Sie bestimmte Einstellungen hinzufügen oder ändern möchten. Im folgenden Beispiel wird ein
applicationIdSuffix
für den Debug-Build-Typ angegeben und ein Staging-Build-Typ konfiguriert, der mit Einstellungen aus dem Debug-Build-Typ initialisiert wird:
Kotlin
android { defaultConfig { manifestPlaceholders["hostName"] = "www.example.com" ... } buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } getByName("debug") { applicationIdSuffix = ".debug" isDebuggable = true } /** * The `initWith` property lets you copy configurations from other build types, * then configure only the settings you want to change. This one copies the debug build * type, and then changes the manifest placeholder and application ID. */ create("staging") { initWith(getByName("debug")) manifestPlaceholders["hostName"] = "internal.example.com" applicationIdSuffix = ".debugStaging" } } }
Cool
android { defaultConfig { manifestPlaceholders = [hostName:"www.example.com"] ... } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" debuggable true } /** * The `initWith` property lets you copy configurations from other build types, * then configure only the settings you want to change. This one copies the debug build * type, and then changes the manifest placeholder and application ID. */ staging { initWith debug manifestPlaceholders = [hostName:"internal.example.com"] applicationIdSuffix ".debugStaging" } } }
Hinweis: Wenn Sie Änderungen an einer Build-Konfigurationsdatei vornehmen, muss Ihr Projekt in Android Studio mit der neuen Konfiguration synchronisiert werden. Klicken Sie zum Synchronisieren Ihres Projekts auf Jetzt synchronisieren in der Benachrichtigungsleiste, die angezeigt wird, wenn Sie eine Änderung vornehmen, oder klicken Sie in der Symbolleiste auf Projekt synchronisieren . Wenn Android Studio Fehler bei der Konfiguration feststellt, wird das Problem im Fenster Nachrichten beschrieben.
Weitere Informationen zu allen Attributen, die Sie mit Build-Typen konfigurieren können, finden Sie in der
Referenz zu BuildType
.
Produktgeschmacksrichtungen konfigurieren
Das Erstellen von Produkt-Geschmacksrichtungen ähnelt dem Erstellen von Build-Typen. Fügen Sie dem Block productFlavors
in der Build-Konfiguration Produkt-Varianten hinzu und nehmen Sie die gewünschten Einstellungen vor.
Die Produkt-Varianten unterstützen dieselben Attribute wie defaultConfig
, da defaultConfig
tatsächlich zur Klasse
ProductFlavor
gehört. Das bedeutet, dass Sie die Basiskonfiguration für alle Flavor im Block defaultConfig
bereitstellen können und jede Variante einen dieser Standardwerte, z. B. den applicationId
, ändern kann. Weitere Informationen zur Anwendungs-ID finden Sie unter Anwendungs-ID festlegen.
Hinweis: Du musst trotzdem noch einen Paketnamen mithilfe des Attributs package
in der Manifestdatei main/
angeben. Sie müssen diesen Paketnamen auch in Ihrem Quellcode verwenden, um auf die R
-Klasse zu verweisen oder um relative Aktivitäten oder Dienstregistrierungen aufzulösen. Auf diese Weise kannst du applicationId
verwenden, um jedem Produktgeschmack eine eindeutige ID für die Verpackung und den Vertrieb zuzuweisen, ohne deinen Quellcode ändern zu müssen.
Alle Geschmacksrichtungen müssen zu einer benannten Geschmacksdimension gehören, d. h. eine Gruppe von Produktaromen. Sie müssen einer Flavor-Dimension alle Geschmacksrichtungen zuweisen. Andernfalls erhalten Sie den folgenden Build-Fehler.
Error: All flavors must now belong to a named flavor dimension. The flavor 'flavor_name' is not assigned to a flavor dimension.
Wenn für ein bestimmtes Modul nur eine Flavor-Dimension angegeben ist, weist das Android-Gradle-Plug-in dieser Dimension automatisch alle Varianten des Moduls zu.
Im folgenden Codebeispiel wird eine Flavor-Dimension mit dem Namen „version“ erstellt und die Produkt-Flavors „demo“ und „full“ hinzugefügt. Diese Geschmacksrichtungen haben ihre eigenen
applicationIdSuffix
und versionNameSuffix
:
Kotlin
android { ... defaultConfig {...} buildTypes { getByName("debug"){...} getByName("release"){...} } // Specifies one flavor dimension. flavorDimensions += "version" productFlavors { create("demo") { // Assigns this product flavor to the "version" flavor dimension. // If you are using only one dimension, this property is optional, // and the plugin automatically assigns all the module's flavors to // that dimension. dimension = "version" applicationIdSuffix = ".demo" versionNameSuffix = "-demo" } create("full") { dimension = "version" applicationIdSuffix = ".full" versionNameSuffix = "-full" } } }
Cool
android { ... defaultConfig {...} buildTypes { debug{...} release{...} } // Specifies one flavor dimension. flavorDimensions "version" productFlavors { demo { // Assigns this product flavor to the "version" flavor dimension. // If you are using only one dimension, this property is optional, // and the plugin automatically assigns all the module's flavors to // that dimension. dimension "version" applicationIdSuffix ".demo" versionNameSuffix "-demo" } full { dimension "version" applicationIdSuffix ".full" versionNameSuffix "-full" } } }
Hinweis:Wenn du eine alte App hast, die vor August 2021 erstellt wurde und über APKs bei Google Play vertrieben wird, musst du allen Varianten denselben applicationId
-Wert zuweisen und jeder Variante eine andere versionCode
zuweisen, um deine App über die Unterstützung für mehrere APKs in Google Play anzubieten. Wenn du verschiedene Varianten deiner App als separate Apps bei Google Play vertreiben möchtest, musst du jeder Variante eine andere applicationId
zuweisen.
Nachdem Sie Ihre Produkt-Geschmacksrichtungen erstellt und konfiguriert haben, klicken Sie in der Benachrichtigungsleiste auf Jetzt synchronisieren. Nach Abschluss der Synchronisierung erstellt Gradle automatisch Build-Varianten anhand Ihrer Build-Typen und Produkt-Varianten und benennt sie nach <product-flavor><Build-Type>
. Wenn Sie beispielsweise die Produkt-Varianten „Demo“ und „Vollständig“ erstellt und die standardmäßigen Build-Typen „Debug“ und „Release“ beibehalten haben, erstellt Gradle die folgenden Build-Varianten:
-
demoDebug
-
demoRelease
-
fullDebug
-
fullRelease
Klicken Sie auf Build > Build-Variante auswählen und wählen Sie eine Build-Variante aus dem Menü aus, um festzulegen, welche Build-Variante erstellt und ausgeführt werden soll. Wenn Sie jede Build-Variante mit ihren eigenen Features und Ressourcen anpassen möchten, müssen Sie Quellsätze erstellen und verwalten, wie auf dieser Seite beschrieben.
Anwendungs-ID für Build-Varianten ändern
Wenn Sie ein APK oder AAB für Ihre App erstellen, taggen die Build-Tools die App wie im folgenden Beispiel mit der App-ID, die im Block defaultConfig
der Datei build.gradle.kts
definiert ist. Wenn Sie jedoch verschiedene Versionen Ihrer App erstellen möchten, die als separate Einträge im Google Play Store angezeigt werden, z. B. eine kostenlose und eine Pro-Version, müssen Sie separate Build-Varianten erstellen, die jeweils eine andere App-ID haben.
Definieren Sie in diesem Fall jede Build-Variante als separaten Produkt-Geschmacks. Für jede Variante im productFlavors
-Block können Sie das Attribut applicationId
neu definieren oder stattdessen ein Segment mit applicationIdSuffix
an die Standardanwendungs-ID anhängen, wie hier gezeigt:
Kotlin
android { defaultConfig { applicationId = "com.example.myapp" } productFlavors { create("free") { applicationIdSuffix = ".free" } create("pro") { applicationIdSuffix = ".pro" } } }
Cool
android { defaultConfig { applicationId "com.example.myapp" } productFlavors { free { applicationIdSuffix ".free" } pro { applicationIdSuffix ".pro" } } }
In diesem Fall lautet die Anwendungs-ID für den Produkt-Flavor "com.example.myapp.free".
Sie können auch applicationIdSuffix
verwenden, um ein Segment basierend auf Ihrem Build-Typ anzuhängen, wie hier gezeigt:
Kotlin
android { ... buildTypes { getByName("debug") { applicationIdSuffix = ".debug" } } }
Cool
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
Da Gradle die Build-Typkonfiguration nach dem Produkt-Flavor anwendet, lautet die Anwendungs-ID für die Build-Variante „free debug“ „com.example.myapp.free.debug“. Dies ist nützlich, wenn sowohl die Fehlerbehebung als auch der Release-Build auf demselben Gerät ausgeführt werden sollen, da keine zwei Apps dieselbe Anwendungs-ID haben können.
Wenn Sie eine alte App haben, die vor August 2021 erstellt wurde und über APKs bei Google Play vertrieben wird, und denselben App-Eintrag verwenden möchten, um mehrere APKs zu vertreiben, die jeweils auf eine andere Gerätekonfiguration wie etwa das API-Level ausgerichtet sind, müssen Sie dieselbe App-ID für jede Build-Variante verwenden, aber jedem APK ein anderesversionCode
zuweisen. Weitere Informationen findest du unter Unterstützung mehrerer APKs. Die Veröffentlichung mit AABs ist nicht betroffen, da ein einzelnes Artefakt verwendet wird, das standardmäßig einen einzigen Versionscode und eine einzige Anwendungs-ID verwendet.
Tipp:Wenn Sie in Ihrer Manifestdatei auf die Anwendungs-ID verweisen müssen, können Sie den Platzhalter ${applicationId}
in einem beliebigen Manifestattribut verwenden. Während eines Builds ersetzt Gradle dieses Tag durch die tatsächliche Anwendungs-ID. Weitere Informationen finden Sie unter Build-Variablen in das Manifest einfügen.
Kombinieren Sie mehrere Produktsorten mit Geschmacksdimensionen
In einigen Fällen möchten Sie möglicherweise Konfigurationen aus mehreren Produkt-Varianten kombinieren. Beispielsweise können Sie unterschiedliche Konfigurationen für die „vollständigen“ und „Demo“-Produkt-Varianten erstellen, die auf der API-Ebene basieren. Dazu können Sie mit dem Android-Gradle-Plug-in mehrere Gruppen von Produkt-Flavor-Dimensionen als Flavor-Dimensionen erstellen.
Beim Erstellen Ihrer App kombiniert Gradle eine Produkt-Flavor-Konfiguration aus jeder von Ihnen definierten Flavor-Dimension mit einer Build-Typkonfiguration, um die endgültige Build-Variante zu erstellen. Gradle kombiniert keine Produkt-Geschmacksrichtungen, die zu derselben Geschmacksdimension gehören.
Im folgenden Codebeispiel wird das Attribut
flavorDimensions
verwendet, um die Flavor-Dimension „mode“ zu erstellen, um die Produkt-Varianten „full“ und „demo“ zu gruppieren, und mit der Flavor-Dimension „API“, um Produkt-Flavor-Konfigurationen auf Basis der API-Ebene zu gruppieren:
Kotlin
android { ... buildTypes { getByName("debug") {...} getByName("release") {...} } // Specifies the flavor dimensions you want to use. The order in which you // list the dimensions determines their priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions += listOf("api", "mode") productFlavors { create("demo") { // Assigns this product flavor to the "mode" flavor dimension. dimension = "mode" ... } create("full") { dimension = "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property, with the first dimension having a higher // priority than the second, and so on. create("minApi24") { dimension = "api" minSdk = 24 // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. versionCode = 30000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi24" ... } create("minApi23") { dimension = "api" minSdk = 23 versionCode = 20000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi23" ... } create("minApi21") { dimension = "api" minSdk = 21 versionCode = 10000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi21" ... } } } ...
Cool
android { ... buildTypes { debug {...} release {...} } // Specifies the flavor dimensions you want to use. The order in which you // list the dimensions determines their priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions "api", "mode" productFlavors { demo { // Assigns this product flavor to the "mode" flavor dimension. dimension "mode" ... } full { dimension "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property, with the first dimension having a higher // priority than the second, and so on. minApi24 { dimension "api" minSdkVersion 24 // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. versionCode 30000 + android.defaultConfig.versionCode versionNameSuffix "-minApi24" ... } minApi23 { dimension "api" minSdkVersion 23 versionCode 20000 + android.defaultConfig.versionCode versionNameSuffix "-minApi23" ... } minApi21 { dimension "api" minSdkVersion 21 versionCode 10000 + android.defaultConfig.versionCode versionNameSuffix "-minApi21" ... } } } ...
Die Anzahl der von Gradle erstellten Build-Varianten entspricht der Anzahl der Geschmacksrichtungen in jeder Flavor-Dimension und der Anzahl der von Ihnen konfigurierten Build-Typen. Wenn Gradle jede Build-Variante oder die entsprechenden Artefakte benennt, werden zuerst die Produkt-Varianten angezeigt, die zur Flavor-Dimension mit höherer Priorität gehören, gefolgt von denen aus Dimensionen mit niedrigerer Priorität und schließlich dem Build-Typ.
Am Beispiel der vorherigen Build-Konfiguration erstellt Gradle insgesamt 12 Build-Varianten mit folgendem Namensschema:
- Build-Variante:
[minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
- Entsprechendes APK:
app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
- Beispiel:
- Build-Variante:
minApi24DemoDebug
- Entsprechendes APK:
app-minApi24-demo-debug.apk
Zusätzlich zu den Quellsatz-Verzeichnissen, die Sie für jede einzelne Produkt-Variante und jede Build-Variante erstellen können, können Sie auch Quellsatz-Verzeichnisse für jede Kombination von Produkt-Varianten erstellen. Sie können beispielsweise Java-Quellen erstellen und dem Verzeichnis src/demoMinApi24/java/
hinzufügen. Gradle verwendet diese Quellen dann nur beim Erstellen einer Variante, die diese beiden Produktvarianten kombiniert.
Quell-Sets, die Sie für Produkt-Geschmackskombinationen erstellen, haben eine höhere Priorität als Quell-Sets, die zu den einzelnen Produkt-Flavor-Kombinationen gehören. Weitere Informationen zu Quellsätzen und zum Zusammenführen von Ressourcen durch Gradle finden Sie im Abschnitt zum Erstellen von Quellsätzen.
Varianten filtern
Gradle erstellt eine Build-Variante für jede mögliche Kombination der von Ihnen konfigurierten Produkt-Varianten und Build-Typen. Es kann jedoch vorkommen, dass es bestimmte Build-Varianten gibt, die Sie nicht benötigen oder im Kontext Ihres Projekts nicht sinnvoll sind. Wenn Sie bestimmte Build-Variantenkonfigurationen entfernen möchten, erstellen Sie in der Datei build.gradle.kts
auf Modulebene einen Variantenfilter.
Nehmen wir als Beispiel die Build-Konfiguration aus dem vorherigen Abschnitt an und nehmen wir an, Sie möchten nur API-Level 23 und höher für die Demoversion der App unterstützen. Mit dem Block
variantFilter
können Sie alle Build-Variantenkonfigurationen herausfiltern, die die Produkt-Varianten „minApi21“ und „Demo“ kombinieren:
Kotlin
android { ... buildTypes {...} flavorDimensions += listOf("api", "mode") productFlavors { create("demo") {...} create("full") {...} create("minApi24") {...} create("minApi23") {...} create("minApi21") {...} } } androidComponents { beforeVariants { variantBuilder -> // To check for a certain build type, use variantBuilder.buildType == "<buildType>" if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) { // Gradle ignores any variants that satisfy the conditions above. variantBuilder.enable = false } } } ...
Cool
android { ... buildTypes {...} flavorDimensions "api", "mode" productFlavors { demo {...} full {...} minApi24 {...} minApi23 {...} minApi21 {...} } variantFilter { variant -> def names = variant.flavors*.name // To check for a certain build type, use variant.buildType.name == "<buildType>" if (names.contains("minApi21") && names.contains("demo")) { // Gradle ignores any variants that satisfy the conditions above. setIgnore(true) } } } ...
Nachdem Sie der Build-Konfiguration einen Variantenfilter hinzugefügt und in der Benachrichtigungsleiste auf Jetzt synchronisieren geklickt haben, ignoriert Gradle alle Build-Varianten, die die von Ihnen angegebenen Bedingungen erfüllen. Die Build-Varianten werden nicht mehr im Menü angezeigt, wenn Sie in der Menüleiste auf Build > Build-Variante auswählen oder in der Symbolleiste des Toolfensters auf Build-Varianten klicken.
Quellsätze erstellen
Standardmäßig erstellt Android Studio den main/
-Quellsatz und die Verzeichnisse für alles, was Sie für alle Ihre Build-Varianten freigeben möchten. Sie können jedoch neue Quellsätze erstellen, um genau zu steuern, welche Dateien Gradle für bestimmte Build-Typen, Produkt-Varianten, Kombinationen von Produkt-Varianten (bei Verwendung von Flavor-Dimensionen) und Build-Varianten kompiliert.
Sie können beispielsweise grundlegende Funktionen im Quellsatz main/
definieren und mit Produkt-Flavor-Quellsets das Branding Ihrer App für verschiedene Clients ändern. Sie können aber auch spezielle Berechtigungen und Logging-Funktionen nur für Build-Varianten einbinden, die den Build-Typ „Debug“ verwenden.
Gradle erwartet, dass die Quelldateien und -verzeichnisse auf eine bestimmte Weise organisiert sind, ähnlich wie das main/
-Quellset. Gradle erwartet beispielsweise, dass sich Kotlin- oder Java-Klassendateien, die für Ihren Build-Typ „debug“ spezifisch sind, im Verzeichnis src/debug/kotlin/
oder src/debug/java/
befinden.
Das Android-Gradle-Plug-in bietet eine nützliche Gradle-Aufgabe, die Ihnen zeigt, wie Sie Ihre Dateien für jeden Ihrer Build-Typen, Produkt-Geschmacks und Build-Varianten organisieren. Im folgenden Beispiel aus der Aufgabenausgabe wird beispielsweise beschrieben, wo Gradle erwartet, dass er bestimmte Dateien für den Build-Typ „debug“ findet:
------------------------------------------------------------ Project :app ------------------------------------------------------------ ... debug ---- Compile configuration: debugCompile build.gradle name: android.sourceSets.debug Java sources: [app/src/debug/java] Kotlin sources: [app/src/debug/kotlin, app/src/debug/java] Manifest file: app/src/debug/AndroidManifest.xml Android resources: [app/src/debug/res] Assets: [app/src/debug/assets] AIDL sources: [app/src/debug/aidl] RenderScript sources: [app/src/debug/rs] JNI sources: [app/src/debug/jni] JNI libraries: [app/src/debug/jniLibs] Java-style resources: [app/src/debug/resources]
So rufen Sie diese Ausgabe auf:
- Klicken Sie in der Leiste des Toolfensters auf Gradle.
Gehen Sie zu MyApplication > Tasks > android und doppelklicken Sie auf sourceSets.
Damit der Ordner Tasks angezeigt wird, müssen Sie Gradle die Aufgabenliste während der Synchronisierung erstellen lassen. Das funktioniert so:
- Klicken Sie auf Datei > Einstellungen > Experimentell (Android Studio > Einstellungen > Experimentell unter macOS).
- Heben Sie die Auswahl von Do not build Gradle task list during Gradle sync (Gradle-Aufgabenliste während Gradle-Synchronisierung nicht erstellen) auf.
- Nachdem Gradle die Aufgabe ausgeführt hat, wird das Fenster Run mit der Ausgabe geöffnet.
Hinweis: Die Aufgabenausgabe zeigt Ihnen auch, wie Sie Quellsätze für Dateien organisieren, die Sie zum Ausführen von Tests für Ihre Anwendung verwenden möchten, z. B. die Testquellensätze test/
und androidTest/
.
Wenn Sie eine neue Build-Variante erstellen, erstellt Android Studio nicht das Quellverzeichnis für Sie, bietet Ihnen aber einige hilfreiche Optionen. So erstellen Sie beispielsweise nur das Verzeichnis java/
für Ihren Build-Typ „debug“:
- Öffnen Sie den Bereich Projekt und wählen Sie oben im Menü die Ansicht Projekt aus.
- Zu
MyProject/app/src/
navigieren - Klicken Sie mit der rechten Maustaste auf das Verzeichnis
src
und wählen Sie Neu > Verzeichnis aus. - Wählen Sie im Menü unter Gradle Source Sets die Option full/java aus.
- Drücken Sie die Eingabetaste.
Android Studio erstellt ein Quellsatzverzeichnis für Ihren Debug-Build-Typ und erstellt dann darin das Verzeichnis java/
. Alternativ kann Android Studio die Verzeichnisse für Sie erstellen, wenn Sie Ihrem Projekt eine neue Datei für eine bestimmte Build-Variante hinzufügen.
So erstellen Sie beispielsweise eine XML-Datei mit Werten für Ihren Build-Typ „debug“:
- Klicken Sie im Bereich Projekt mit der rechten Maustaste auf das Verzeichnis
src
und wählen Sie Neu > XML > XML-Datei mit Werten aus. - Geben Sie den Namen für die XML-Datei ein oder behalten Sie den Standardnamen bei.
- Wählen Sie im Menü neben Target Source Set (Zielquellensatz) die Option debug aus.
- Klicken Sie auf Fertig.
Da der Build-Typ "debug" als Zielquellensatz angegeben wurde, erstellt Android Studio beim Erstellen der XML-Datei automatisch die erforderlichen Verzeichnisse. Die resultierende Verzeichnisstruktur sieht aus wie in Abbildung 1.
![](https://developer.android.google.cn/static/images/tools/debug-directories_2-1_2x.png?authuser=6&hl=de)
Abbildung 1: Neue Quellsatzverzeichnisse für den Build-Typ „debug“.
Das Symbol aktiver Quellensätze weist einen grünen Indikator darauf hin, dass sie aktiv sind. Das debug
-Quellset hat das Suffix [main]
, um zu zeigen, dass es mit dem main
-Quellsatz zusammengeführt wird.
Mit demselben Verfahren können Sie auch Quellsatz-Verzeichnisse für Produkt-Varianten wie src/demo/
erstellen und Varianten wie src/demoDebug/
erstellen. Darüber hinaus können Sie Testquellensätze erstellen, die auf bestimmte Build-Varianten ausgerichtet sind, z. B. src/androidTestDemoDebug/
. Weitere Informationen finden Sie unter Quellsätze testen.
Standardkonfigurationen des Quellsatzes ändern
Wenn Sie Quellen haben, die nicht in der von Gradle erwarteten Standarddateistruktur für Quelldateien organisiert sind (wie im vorherigen Abschnitt zum Erstellen von Quellsätzen beschrieben), können Sie mit dem Block
sourceSets
ändern, wo Gradle Dateien für die einzelnen Komponenten eines Quellsatzes erfasst.
Der sourceSets
-Block muss sich im android
-Block befinden. Die Quelldateien müssen nicht neu abgelegt werden. Sie müssen Gradle nur die Pfade relativ zur Datei build.gradle.kts
auf Modulebene zur Verfügung stellen, in denen Gradle Dateien für jede Quellsatzkomponente finden kann. Informationen dazu, welche Komponenten sich konfigurieren lassen und ob sie mehreren Dateien oder Verzeichnissen zugeordnet werden können, finden Sie in der Referenz zur Android Gradle Plugin API.
Im folgenden Codebeispiel werden Quellen aus dem Verzeichnis app/other/
bestimmten Komponenten des Quellsatzes main
zugeordnet und das Stammverzeichnis des Quellsatzes androidTest
geändert:
Kotlin
android { ... // Encapsulates configurations for the main source set. sourceSets.getByName("main") { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.setSrcDirs(listOf("other/java")) // If you list multiple directories, Gradle uses all of them to collect // sources. Because Gradle gives these directories equal priority, if // you define the same resource in more than one directory, you receive an // error when merging resources. The default directory is 'src/main/res'. res.setSrcDirs(listOf("other/res1", "other/res2")) // Note: Avoid specifying a directory that is a parent to one // or more other directories you specify. For example, avoid the following: // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings'] // Specify either only the root 'other/res1' directory or only the // nested 'other/res1/layouts' and 'other/res1/strings' directories. // For each source set, you can specify only one Android manifest. // By default, Android Studio creates a manifest for your main source // set in the src/main/ directory. manifest.srcFile("other/AndroidManifest.xml") ... } // Create additional blocks to configure other source sets. sourceSets.getByName("androidTest") { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying the // configuration below for the androidTest source set, Gradle looks for Java // sources only in the src/tests/java/ directory. setRoot("src/tests") ... } } ...
Cool
android { ... sourceSets { // Encapsulates configurations for the main source set. main { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.srcDirs = ['other/java'] // If you list multiple directories, Gradle uses all of them to collect // sources. Because Gradle gives these directories equal priority, if // you define the same resource in more than one directory, you receive an // error when merging resources. The default directory is 'src/main/res'. res.srcDirs = ['other/res1', 'other/res2'] // Note: Avoid specifying a directory that is a parent to one // or more other directories you specify. For example, avoid the following: // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings'] // Specify either only the root 'other/res1' directory or only the // nested 'other/res1/layouts' and 'other/res1/strings' directories. // For each source set, you can specify only one Android manifest. // By default, Android Studio creates a manifest for your main source // set in the src/main/ directory. manifest.srcFile 'other/AndroidManifest.xml' ... } // Create additional blocks to configure other source sets. androidTest { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying the // configuration below for the androidTest source set, Gradle looks for Java // sources only in the src/tests/java/ directory. setRoot 'src/tests' ... } } } ...
Beachten Sie, dass ein Quellverzeichnis nur zu einem Quellsatz gehören kann. Beispielsweise ist es nicht möglich, dieselben Testquellen sowohl für die Quellgruppen test
als auch für androidTest
freizugeben. Das liegt daran, dass Android Studio separate IntelliJ-Module für jeden Quellsatz erstellt und keine doppelten Inhaltsstämme in Quellsätzen unterstützt.
Mit Quellsätzen erstellen
Sie können Quellsatzverzeichnisse so verwenden, dass sie den Code und die Ressourcen enthalten, die nur mit bestimmten Konfigurationen gepackt werden sollen. Wenn Sie beispielsweise die Build-Variante „demoDebug“ erstellen, die das Kreuzprodukt einer Produkt-Variante „Demo“ und eines Build-Typs „debug“ ist, prüft Gradle diese Verzeichnisse und gibt ihnen die folgende Priorität:
-
src/demoDebug/
(Variantenquellensatz erstellen) -
src/debug/
(Build-Typ-Quellsatz) -
src/demo/
(Menge der Geschmacksquelle des Produkts) -
src/main/
(Hauptquellen festgelegt)
Quellsätze, die für Kombinationen von Produkt-Geschmacksrichtungen erstellt werden, müssen alle Geschmacksdimensionen enthalten. Der Quellsatz der Build-Variante muss beispielsweise die Kombination aus dem Build-Typ und allen Flavor-Dimensionen sein. Das Zusammenführen von Code und Ressourcen mit Ordnern, die mehrere, aber nicht alle Flavor-Dimensionen abdecken, wird nicht unterstützt.
Wenn Sie mehrere Produktaromen kombinieren, wird die Priorität zwischen den Produktsorten durch die Geschmacksdimension bestimmt, zu der sie gehören. Wenn Sie Geschmacksdimensionen mit dem Attribut
android.flavorDimensions
auflisten, haben Produktsorten, die zur ersten von Ihnen aufgelisteten Geschmacksdimension gehören, eine höhere Priorität als die der zweiten Geschmacksdimension und so weiter. Darüber hinaus haben Quellsätze, die Sie für Kombinationen von Produkt-Geschmacksrichtungen erstellen, eine höhere Priorität als Quellsätze, die zu einem einzelnen Produkt-Geschmacks gehören.
Die Prioritätsreihenfolge bestimmt, welcher Quellsatz eine höhere Priorität hat, wenn Gradle Code und Ressourcen kombiniert. Da das demoDebug/
-Quellsatzverzeichnis wahrscheinlich Dateien enthält, die für diese Build-Variante spezifisch sind, verwendet Gradle die Datei im demoDebug/
-Quellsatz, wenn demoDebug/
eine Datei enthält, die auch in debug/
definiert ist. Ebenso weist Gradle Dateien im Build-Typ und für die Produkt-Flavor-Quelle eine höhere Priorität zu als dieselben Dateien in main/
.
Gradle berücksichtigt diese Prioritätsreihenfolge bei der Anwendung der folgenden Build-Regeln:
- Der gesamte Quellcode in den Verzeichnissen
kotlin/
oderjava/
wird zu einer einzigen Ausgabe kompiliert.Hinweis:Bei einer bestimmten Build-Variante gibt Gradle einen Build-Fehler aus, wenn zwei oder mehr Quellsatz-Verzeichnisse gefunden werden, in denen dieselbe Kotlin- oder Java-Klasse definiert ist. Wenn Sie beispielsweise eine Debug-Anwendung erstellen, können Sie nicht sowohl
src/debug/Utility.kt
als auchsrc/main/Utility.kt
definieren, da Gradle diese Verzeichnisse während des Build-Prozesses prüft und einen Fehler vom Typ „Doppelte Klasse“ ausgibt. Wenn Sie verschiedeneUtility.kt
-Versionen für verschiedene Build-Typen verwenden möchten, muss jeder Build-Typ eine eigene Version der Datei definieren und nicht in denmain/
-Quellsatz aufnehmen. - Manifeste werden zu einem einzigen Manifest zusammengeführt. Die Priorität wird in derselben Reihenfolge wie in der Liste im vorherigen Beispiel angegeben. Das heißt, die Manifesteinstellungen für einen Build-Typ überschreiben die Manifesteinstellungen für einen Produkt-Flavor usw. Weitere Informationen finden Sie unter Manifestzusammenführung.
- Dateien in den
values/
-Verzeichnissen werden zusammengeführt. Wenn zwei Dateien denselben Namen haben, z. B. zweistrings.xml
-Dateien, wird die Priorität in derselben Reihenfolge wie in der Liste im vorherigen Beispiel gewährt. Das heißt, Werte, die in einer Datei im Quellsatz des Build-Typs definiert sind, überschreiben die Werte, die in derselben Datei in einem Produkt-Flavor definiert wurden, usw. - Ressourcen in den Verzeichnissen
res/
undasset/
werden zusammengefasst. Wenn Ressourcen mit demselben Namen in zwei oder mehr Quellsätzen definiert sind, wird die Priorität in derselben Reihenfolge wie in der Liste im vorherigen Beispiel zugewiesen. - Gradle verleiht den in Bibliotheksmodulabhängigkeiten enthaltenen Ressourcen und Manifesten beim Erstellen der App die niedrigste Priorität.
Abhängigkeiten deklarieren
Wenn Sie eine Abhängigkeit für eine bestimmte Build-Variante oder einen Testquellsatz konfigurieren möchten, stellen Sie dem Namen der Build-Variante oder des Testquellensatzes vor dem Schlüsselwort Implementation
ein Präfix wie im folgenden Beispiel:
Kotlin
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. "freeImplementation"(project(":mylibrary")) // Adds a remote binary dependency only for local tests. testImplementation("junit:junit:4.12") // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation("com.android.support.test.espresso:espresso-core:3.5.1") }
Cool
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. freeImplementation project(":mylibrary") // Adds a remote binary dependency only for local tests. testImplementation 'junit:junit:4.12' // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.5.1' }
Weitere Informationen zum Konfigurieren von Abhängigkeiten finden Sie unter Build-Abhängigkeiten hinzufügen.
Variantensensitive Abhängigkeitsverwaltung verwenden
Das Android-Gradle-Plug-in 3.0.0 und höher enthält einen neuen Abhängigkeitsmechanismus, der Varianten automatisch erkennt, wenn eine Bibliothek verwendet wird. Das bedeutet, dass die debug
-Variante einer App automatisch die debug
-Variante einer Bibliothek nutzt usw. Das funktioniert auch bei Verwendung von Flavors: Die freeDebug
-Variante einer App nutzt die freeDebug
-Variante einer Bibliothek.
Damit das Plug-in Varianten genau abgleichen kann, müssen Sie für Fälle, in denen eine direkte Zuordnung nicht möglich ist, übereinstimmende Fallbacks bereitstellen, wie im folgenden Abschnitt beschrieben.
Angenommen, Ihre Anwendung konfiguriert einen Build-Typ namens „Staging“, eine der Bibliotheksabhängigkeiten jedoch nicht. Wenn das Plug-in versucht, die Staging-Version Ihrer Anwendung zu erstellen, weiß es nicht, welche Version der Bibliothek verwendet werden soll. Stattdessen wird eine Fehlermeldung wie diese angezeigt:
Error:Failed to resolve: Could not resolve project :mylibrary. Required by: project :app
Build-Fehler im Zusammenhang mit dem Variantenabgleich beheben
Das Plug-in enthält DSL-Elemente, mit denen Sie steuern können, wie Gradle Situationen behebt, in denen eine direkte Variantenübereinstimmung zwischen einer App und einer Abhängigkeit nicht möglich ist.
Im Folgenden finden Sie eine Liste von Problemen im Zusammenhang mit dem variantenbasierten Abhängigkeitsabgleich und wie sie mithilfe von DSL-Eigenschaften behoben werden können:Deine App enthält einen Build-Typ, den es bei einer Bibliotheksabhängigkeit nicht gibt.
Ihre Anwendung enthält beispielsweise den Build-Typ „Staging“, aber eine Abhängigkeit umfasst nur die Build-Typen „Debug“ und „Release“.
Wenn eine Bibliotheksabhängigkeit einen Build-Typ enthält, den es bei Ihrer App nicht gibt, gibt es kein Problem. Das liegt daran, dass das Plug-in diesen Build-Typ niemals aus der Abhängigkeit anfordert.
Verwenden Sie
matchingFallbacks
, um alternative Übereinstimmungen für einen bestimmten Build-Typ anzugeben, wie hier gezeigt:Kotlin
// In the app's build.gradle.kts file. android { buildTypes { getByName("debug") {} getByName("release") {} create("staging") { // Specifies a sorted list of fallback build types that the // plugin can try to use when a dependency does not include a // "staging" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks += listOf("debug", "qa", "release") } } }
Cool
// In the app's build.gradle file. android { buildTypes { debug {} release {} staging { // Specifies a sorted list of fallback build types that the // plugin can try to use when a dependency does not include a // "staging" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks = ['debug', 'qa', 'release'] } } }
Für eine bestimmte Flavor-Dimension, die sowohl in der App als auch in ihrer Bibliotheksabhängigkeit vorhanden ist, enthält deine App Flavors, die die Bibliothek nicht enthält.
Beispielsweise enthalten sowohl die Anwendungs- als auch die Bibliotheksabhängigkeiten die Flavor-Dimension „tier“. Die Dimension „Stufe“ in der App enthält jedoch die Varianten „kostenlos“ und „kostenpflichtig“, aber eine Abhängigkeit umfasst nur die Varianten „Demo“ und „Kostenpflichtig“ für dieselbe Dimension.
Beachten Sie, dass für eine bestimmte Flavor-Dimension, die sowohl in der App als auch in ihren Bibliotheksabhängigkeiten vorhanden ist, kein Problem auftritt, wenn eine Bibliothek einen Produkt-Flavor enthält, den Ihre App nicht enthält. Das liegt daran, dass das Plug-in diese Flasche aus der Abhängigkeit nie anfordert.
Verwende
matchingFallbacks
, um alternative Übereinstimmungen für die „kostenlose“ Produktvariante der App anzugeben, wie hier gezeigt:Kotlin
// In the app's build.gradle.kts file. android { defaultConfig{ // Don't configure matchingFallbacks in the defaultConfig block. // Instead, specify fallbacks for a given product flavor in the // productFlavors block, as shown below. } flavorDimensions += "tier" productFlavors { create("paid") { dimension = "tier" // Because the dependency already includes a "paid" flavor in its // "tier" dimension, you don't need to provide a list of fallbacks // for the "paid" flavor. } create("free") { dimension = "tier" // Specifies a sorted list of fallback flavors that the plugin // can try to use when a dependency's matching dimension does // not include a "free" flavor. Specify as many // fallbacks as you like; the plugin selects the first flavor // that's available in the dependency's "tier" dimension. matchingFallbacks += listOf("demo", "trial") } } }
Cool
// In the app's build.gradle file. android { defaultConfig{ // Don't configure matchingFallbacks in the defaultConfig block. // Instead, specify fallbacks for a given product flavor in the // productFlavors block, as shown below. } flavorDimensions 'tier' productFlavors { paid { dimension 'tier' // Because the dependency already includes a "paid" flavor in its // "tier" dimension, you don't need to provide a list of fallbacks // for the "paid" flavor. } free { dimension 'tier' // Specifies a sorted list of fallback flavors that the plugin // can try to use when a dependency's matching dimension does // not include a "free" flavor. Specify as many // fallbacks as you like; the plugin selects the first flavor // that's available in the dependency's "tier" dimension. matchingFallbacks = ['demo', 'trial'] } } }
Eine Bibliotheksabhängigkeit umfasst eine Flavor-Dimension, die Ihre App nicht enthält.
Eine Bibliotheksabhängigkeit enthält beispielsweise Flavors für eine „minApi“-Dimension, Ihre Anwendung aber nur Flavors für die Dimension „tier“. Wenn Sie die Version „freeDebug“ Ihrer Anwendung erstellen möchten, weiß das Plug-in nicht, ob die Version „minApi23Debug“ oder „minApi18Debug“ der Abhängigkeit verwendet werden soll.
Wenn Ihre App eine Flavor-Dimension enthält, die es bei einer Bibliotheksabhängigkeit nicht der Fall ist, gibt es kein Problem. Das liegt daran, dass das Plug-in nur die Varianten der Dimensionen zuordnet, die in der Abhängigkeit vorhanden sind. Wenn eine Abhängigkeit beispielsweise keine Dimension für ABIs enthält, verwendet die Version „freeX86Debug“ Ihrer App die Version „freeDebug“ der Abhängigkeit.
Verwenden Sie
missingDimensionStrategy
imdefaultConfig
-Block, um den Standard-Flavor anzugeben, den das Plug-in aus jeder fehlenden Dimension auswählen soll, wie im folgenden Beispiel gezeigt. Sie können Ihre Auswahl im BlockproductFlavors
auch überschreiben, um für jede Variante eine andere Abgleichsstrategie für eine fehlende Dimension anzugeben.Kotlin
// In the app's build.gradle.kts file. android { defaultConfig{ // Specifies a sorted list of flavors that the plugin can try to use from // a given dimension. This tells the plugin to select the "minApi18" flavor // when encountering a dependency that includes a "minApi" dimension. // You can include additional flavor names to provide a // sorted list of fallbacks for the dimension. missingDimensionStrategy("minApi", "minApi18", "minApi23") // Specify a missingDimensionStrategy property for each // dimension that exists in a local dependency but not in your app. missingDimensionStrategy("abi", "x86", "arm64") } flavorDimensions += "tier" productFlavors { create("free") { dimension = "tier" // You can override the default selection at the product flavor // level by configuring another missingDimensionStrategy property // for the "minApi" dimension. missingDimensionStrategy("minApi", "minApi23", "minApi18") } create("paid") {} } }
Cool
// In the app's build.gradle file. android { defaultConfig{ // Specifies a sorted list of flavors that the plugin can try to use from // a given dimension. This tells the plugin to select the "minApi18" flavor // when encountering a dependency that includes a "minApi" dimension. // You can include additional flavor names to provide a // sorted list of fallbacks for the dimension. missingDimensionStrategy 'minApi', 'minApi18', 'minApi23' // Specify a missingDimensionStrategy property for each // dimension that exists in a local dependency but not in your app. missingDimensionStrategy 'abi', 'x86', 'arm64' } flavorDimensions 'tier' productFlavors { free { dimension 'tier' // You can override the default selection at the product flavor // level by configuring another missingDimensionStrategy property // for the 'minApi' dimension. missingDimensionStrategy 'minApi', 'minApi23', 'minApi18' } paid {} } }
Weitere Informationen finden Sie in der DSL-Referenz zum Android-Gradle-Plug-in unter matchingFallbacks
und missingDimensionStrategy
.
Signatureinstellungen konfigurieren
Gradle signiert nur dann das APK oder AAB Ihres Release-Builds, wenn Sie explizit eine Signaturkonfiguration für diesen Build definieren. Falls du noch keinen Signaturschlüssel hast, kannst du mit Android Studio einen Uploadschlüssel und einen Schlüsselspeicher generieren.
So konfigurieren Sie die Signaturkonfigurationen für Ihren Release-Build-Typ manuell mithilfe von Gradle-Build-Konfigurationen:
- Erstellen Sie einen Schlüsselspeicher. Ein Schlüsselspeicher ist eine Binärdatei, die eine Reihe privater Schlüssel enthält. Sie müssen Ihren Schlüsselspeicher an einem sicheren Ort aufbewahren.
- Erstellen Sie einen privaten Schlüssel. Ein privater Schlüssel wird verwendet, um deine App für den Vertrieb zu signieren. Er wird niemals in die App integriert oder an nicht autorisierte Dritte weitergegeben.
-
Fügen Sie der Datei
build.gradle.kts
auf Modulebene die Signaturkonfiguration hinzu:Kotlin
... android { ... defaultConfig {...} signingConfigs { create("release") { storeFile = file("myreleasekey.keystore") storePassword = "password" keyAlias = "MyReleaseKey" keyPassword = "password" } } buildTypes { getByName("release") { ... signingConfig = signingConfigs.getByName("release") } } }
Cool
... android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } } }
Hinweis: Es ist keine gute Sicherheitsmaßnahme, die Passwörter für den Releaseschlüssel und den Schlüsselspeicher in die Build-Datei aufzunehmen. Konfigurieren Sie die Build-Datei stattdessen so, dass diese Passwörter aus Umgebungsvariablen abgerufen werden, oder der Build-Prozess fordert Sie zur Eingabe dieser Passwörter auf.
So erhalten Sie diese Passwörter aus Umgebungsvariablen:
Kotlin
storePassword = System.getenv("KSTOREPWD") keyPassword = System.getenv("KEYPWD")
Cool
storePassword System.getenv("KSTOREPWD") keyPassword System.getenv("KEYPWD")
Alternativ können Sie den Schlüsselspeicher aus einer lokalen Attributdatei laden. Fügen Sie diese Datei aus Sicherheitsgründen nicht der Versionsverwaltung hinzu. Richten Sie es stattdessen lokal für jeden Entwickler ein. Weitere Informationen finden Sie unter Signaturinformationen aus Build-Dateien entfernen.
Wenn dieser Vorgang abgeschlossen ist, kannst du deine App vertreiben und bei Google Play veröffentlichen.
Warnung:Bewahren Sie Ihren Schlüsselspeicher und Ihren privaten Schlüssel an einem sicheren Ort auf und sichern Sie sich sichere Back-ups. Wenn du die Play App-Signatur verwendest und deinen Uploadschlüssel verlierst, kannst du über die Play Console das Zurücksetzen anfordern. Wenn du eine App ohne Play App Signing veröffentlichst (bei Apps, die vor August 2021 erstellt wurden) und du den App-Signaturschlüssel verlierst, kannst du keine Updates mehr für deine App veröffentlichen, da du immer alle Versionen deiner App mit demselben Schlüssel signieren musst.
Wear OS-Apps signieren
Wenn du Wear OS-Apps veröffentlichst, müssen sowohl das Smartwatch-APK als auch das optionale Smartphone-APK mit demselben Schlüssel signiert sein. Weitere Informationen zum Verpacken und Signieren von Wear OS-Apps findest du unter Wear-Apps im Paket anbieten und vertreiben.