Auf dieser Seite erfahren Sie, wie Sie Build-Varianten konfigurieren, um verschiedene Versionen Ihrer App aus einem einzigen Projekt zu erstellen, und wie Sie Ihre Abhängigkeiten und Signaturkonfigurationen richtig verwalten.
Jede Build-Variante stellt eine andere Version Ihrer App dar, die Sie erstellen können. Du kannst beispielsweise eine kostenlose Version deiner App mit einer begrenzten Anzahl von Inhalten und eine kostenpflichtige Version mit mehr Inhalten erstellen. Du kannst auch verschiedene Versionen deiner App erstellen, die auf unterschiedliche Geräte ausgerichtet sind, basierend auf dem API-Level oder anderen Gerätevarianten.
Build-Varianten sind das Ergebnis der Verwendung eines bestimmten Regelsatzes durch Gradle, um Einstellungen, Code und Ressourcen zu kombinieren, die in Ihren Build-Typen und Produktvarianten konfiguriert sind. Build-Varianten werden nicht direkt konfiguriert, sondern Sie definieren die Build-Typen und Produktvarianten, aus denen sie bestehen.
Beispielsweise können für eine Produktvariante „Demo“ bestimmte Funktionen und Geräteanforderungen wie benutzerdefinierter Quellcode, Ressourcen und Mindest-API-Level festgelegt werden, während für den Build-Typ „Debug“ andere Build- und Paketeinstellungen wie Debugging-Optionen und Signaturschlüssel gelten. Die Build-Variante, die diese beiden kombiniert, ist die „demoDebug“-Version Ihrer App. Sie enthält eine Kombination der Konfigurationen und Ressourcen, die in der Produktvariante „demo“, dem Build-Typ „debug“ und dem Source-Set main/ enthalten sind.
Build-Typen konfigurieren
Build-Typen können im Block android der Datei build.gradle.kts auf Modulebene erstellt und konfiguriert werden. Wenn Sie ein neues Modul erstellen, erstellt Android Studio automatisch die Build-Typen „Debug“ und „Release“. Obwohl der Debug-Build-Typ nicht in der Build-Konfigurationsdatei angezeigt wird, wird er von Android Studio mit debuggable
true konfiguriert. So kannst du die App auf sicheren Android-Geräten debuggen und die App-Signatur mit einem generischen Debug-Schlüsselspeicher konfigurieren.
Sie können den Build-Typ „Debug“ zu Ihrer Konfiguration hinzufügen, 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 den Einstellungen des Debug-Build-Typs 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" } } }
Groovy
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, müssen Sie Ihr Projekt in Android Studio mit der neuen Konfiguration synchronisieren. Klicken Sie zum Synchronisieren Ihres Projekts in der Benachrichtigungsleiste, die angezeigt wird, wenn Sie eine Änderung vornehmen, auf Jetzt synchronisieren oder in der Symbolleiste auf Projekt synchronisieren
. Wenn Android Studio Fehler in Ihrer Konfiguration feststellt, wird das Fenster Nachrichten angezeigt, in dem das Problem beschrieben wird.
Weitere Informationen zu allen Attributen, die Sie mit Build-Typen konfigurieren können, finden Sie in der
Referenz zu BuildType.
Produktvarianten konfigurieren
Das Erstellen von Produktvarianten ähnelt dem Erstellen von Build-Typen. Fügen Sie dem Block productFlavors in Ihrer Build-Konfiguration Produktvarianten hinzu und legen Sie die gewünschten Einstellungen fest.
Die Produktvarianten unterstützen dieselben Properties wie defaultConfig, da defaultConfig tatsächlich zur Klasse
ProductFlavor gehört. Das bedeutet, dass Sie die Basiskonfiguration für alle Varianten im Block defaultConfig angeben können und jede Variante einen dieser Standardwerte ändern kann, z. B. die applicationId. Weitere Informationen zur Anwendungs-ID finden Sie unter Anwendungs-ID festlegen.
Hinweis: Du musst weiterhin einen Paketnamen mit dem Attribut package in der Manifestdatei main/ angeben. Sie müssen diesen Paketnamen auch in Ihrem Quellcode verwenden, um auf die Klasse R zu verweisen oder um eine relative Aktivitäts- oder Dienstregistrierung aufzulösen. So kannst du mit applicationId jeder Produktvariante eine eindeutige ID für die Paketierung und Verteilung zuweisen, ohne den Quellcode ändern zu müssen.
Alle Varianten müssen zu einer benannten Variantendimension gehören, d. h. einer Gruppe von Produktvarianten. Sie müssen alle Varianten einer Variantendimension 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 ein bestimmtes Modul nur eine Flavor-Dimension angibt, weist das Android-Gradle-Plug-in automatisch alle Flavors des Moduls dieser Dimension zu.
Im folgenden Codebeispiel wird eine Flavor-Dimension namens „version“ erstellt und die Produktvarianten „demo“ und „full“ werden hinzugefügt. Diese Varianten bieten eigene
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" } } }
Groovy
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 Sie eine ältere App (erstellt vor August 2021) haben, die Sie über APKs bei Google Play bereitstellen, und Sie Ihre App mit Unterstützung für mehrere APKs bei Google Play bereitstellen möchten, weisen Sie allen Varianten denselben applicationId-Wert zu und geben Sie jeder Variante einen anderen versionCode. Wenn Sie verschiedene Varianten Ihrer App als separate Apps bei Google Play anbieten möchten, müssen Sie jeder Variante einen anderen applicationId zuweisen.
Nachdem Sie Ihre Produktvarianten erstellt und konfiguriert haben, klicken Sie in der Benachrichtigungsleiste auf Jetzt synchronisieren. Nach Abschluss der Synchronisierung erstellt Gradle automatisch Build-Varianten basierend auf Ihren Build-Typen und Produktvarianten und benennt sie gemäß <product-flavor><Build-Type>. Wenn ihr beispielsweise die Produktvarianten „demo“ und „full“ erstellt und die Standard-Build-Typen „debug“ und „release“ beibehalten habt, erstellt Gradle die folgenden Build-Varianten:
-
demoDebug -
demoRelease -
fullDebug -
fullRelease
Wenn Sie auswählen möchten, welche Build-Variante erstellt und ausgeführt werden soll, rufen Sie Build > Build-Variante auswählen auf und wählen Sie eine Build-Variante aus dem Menü aus. Wenn Sie jede Build-Variante mit eigenen Funktionen und Ressourcen anpassen möchten, müssen Sie Source-Sets 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, wird die App von den Build-Tools mit der Anwendungs-ID gekennzeichnet, die im Block defaultConfig der Datei build.gradle.kts definiert ist, wie im folgenden Beispiel gezeigt. Wenn du jedoch verschiedene Versionen deiner App erstellen möchtest, die als separate Einträge im Google Play Store angezeigt werden, z. B. eine kostenlose und eine Pro-Version, musst du separate Build-Varianten mit jeweils einer anderen Anwendungs-ID erstellen.
In diesem Fall definieren Sie jede Build-Variante als separate Produktvariante. Für jede Variante im productFlavors-Block können Sie das Attribut applicationId neu definieren oder stattdessen mit applicationIdSuffix ein Segment an die Standard-Anwendungs-ID anhängen, wie hier gezeigt:
Kotlin
android { defaultConfig { applicationId = "com.example.myapp" } productFlavors { create("free") { applicationIdSuffix = ".free" } create("pro") { applicationIdSuffix = ".pro" } } }
Groovy
android { defaultConfig { applicationId "com.example.myapp" } productFlavors { free { applicationIdSuffix ".free" } pro { applicationIdSuffix ".pro" } } }
Die Anwendungs-ID für die Produktvariante „free“ lautet dann „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" } } }
Groovy
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
Da Gradle die Build-Typ-Konfiguration nach der Produktvariante anwendet, lautet die Anwendungs-ID für die Build-Variante „free debug“ „com.example.myapp.free.debug“. Das ist nützlich, wenn Sie sowohl den Debug- als auch den Release-Build auf demselben Gerät haben möchten, da keine zwei Apps dieselbe Anwendungs-ID haben können.
Wenn Sie eine ältere App (erstellt vor August 2021) haben, die Sie über APKs bei Google Play vertreiben, und Sie denselben App-Eintrag verwenden möchten, um mehrere APKs zu vertreiben, die jeweils auf eine andere Gerätekonfiguration wie das API-Level ausgerichtet sind, müssen Sie für jede Build-Variante dieselbe Anwendungs-ID verwenden, aber jedem APK einen anderen versionCode zuweisen. Weitere Informationen finden Sie unter Unterstützung für mehrere APKs. Die Veröffentlichung mit AABs ist davon nicht betroffen, da standardmäßig ein einzelnes Artefakt mit einem einzelnen Versionscode und einer einzelnen Anwendungs-ID verwendet wird.
Tipp: Wenn Sie in Ihrer Manifestdatei auf die Anwendungs-ID verweisen müssen, können Sie den Platzhalter ${applicationId} in jedem 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.
Mehrere Produktvarianten mit Flavor-Dimensionen kombinieren
In einigen Fällen kann es sinnvoll sein, Konfigurationen aus mehreren Produktvarianten zu kombinieren. Beispielsweise können Sie unterschiedliche Konfigurationen für die Produktvarianten „Vollversion“ und „Demo“ erstellen, die auf dem API-Level basieren. Dazu können Sie mit dem Android-Gradle-Plug-in mehrere Gruppen von Produktvarianten als Flavor-Dimensionen erstellen.
Beim Erstellen Ihrer App kombiniert Gradle eine Produktvariantenkonfiguration aus jeder von Ihnen definierten Flavor-Dimension mit einer Build-Typ-Konfiguration, um die endgültige Build-Variante zu erstellen. Gradle kombiniert keine Produktvarianten, die zur selben Flavor-Dimension gehören.
Im folgenden Codebeispiel wird das Attribut
flavorDimensions verwendet, um eine Flavor-Dimension „mode“ zu erstellen, mit der die Produktvarianten „full“ und „demo“ gruppiert werden, sowie eine Flavor-Dimension „api“, mit der Produktvariantenkonfigurationen basierend auf dem API-Level gruppiert werden:
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" ... } } } ...
Groovy
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 dem Produkt aus der Anzahl der Varianten in jeder Varianten-Dimension und der Anzahl der von Ihnen konfigurierten Build-Typen. Wenn Gradle die einzelnen Build-Varianten oder entsprechenden Artefakte benennt, werden zuerst die Produktvarianten angezeigt, die zu einer Flavor-Dimension mit höherer Priorität gehören, gefolgt von denen aus Dimensionen mit niedrigerer Priorität und dann vom Build-Typ.
Am Beispiel der vorherigen Build-Konfiguration erstellt Gradle insgesamt 12 Build-Varianten mit dem folgenden Benennungsschema:
- Build-Variante:
[minApi24, minApi23, minApi21][Demo, Full][Debug, Release] - Entsprechende APK:
app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk - Beispiel:
- Build-Variante:
minApi24DemoDebug - Zugehöriges APK:
app-minApi24-demo-debug.apk
Zusätzlich zu den Source-Set-Verzeichnissen, die Sie für jede einzelne Produktvariante und Build-Variante erstellen können, können Sie auch Source-Set-Verzeichnisse für jede Kombination von Produktvarianten erstellen. Beispielsweise können Sie Java-Quellen erstellen und dem Verzeichnis src/demoMinApi24/java/ hinzufügen. Gradle verwendet diese Quellen dann nur, wenn eine Variante erstellt wird, die diese beiden Produktvarianten kombiniert.
Source-Sets, die Sie für Kombinationen von Produktvarianten erstellen, haben eine höhere Priorität als Source-Sets, die zu den einzelnen Produktvarianten gehören. Weitere Informationen zu Source-Sets und dazu, wie Gradle Ressourcen zusammenführt, findest du im Abschnitt Source-Sets erstellen.
Varianten filtern
Gradle erstellt für jede mögliche Kombination der von Ihnen konfigurierten Produktvarianten und Build-Typen eine Build-Variante. Es kann jedoch bestimmte Build-Varianten geben, die Sie nicht benötigen oder die im Kontext Ihres Projekts nicht sinnvoll sind. Wenn Sie bestimmte Build-Variantenkonfigurationen entfernen möchten, erstellen Sie einen Variantenfilter in der Datei build.gradle.kts auf Modulebene.
Angenommen, Sie möchten für die Demoversion der App nur die API-Level 23 und höher unterstützen. Sie können den Block
variantFilter verwenden, um alle Build-Variantenkonfigurationen herauszufiltern, die die Produktvarianten „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 } } } ...
Groovy
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 Ihrer 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 Toolfensterleiste auf Build-Varianten
klicken.
Source-Sets erstellen
Standardmäßig erstellt Android Studio das main/-Source-Set und die Verzeichnisse für alles, was Sie zwischen allen Build-Varianten teilen möchten. Sie können jedoch neue Source-Sets erstellen, um genau zu steuern, welche Dateien Gradle für bestimmte Build-Typen, Produktvarianten, Kombinationen von Produktvarianten (bei Verwendung von Flavor-Dimensionen) und Build-Varianten kompiliert und verpackt.
Beispielsweise können Sie grundlegende Funktionen im Source-Set main/ definieren und Source-Sets für Produktvarianten verwenden, um das Branding Ihrer App für verschiedene Kunden zu ändern oder spezielle Berechtigungen und Logging-Funktionen nur für Build-Varianten einzuschließen, die den Build-Typ „Debug“ verwenden.
Gradle erwartet, dass die Dateien und Verzeichnisse des Source-Sets auf eine bestimmte Weise organisiert sind, ähnlich wie beim Source-Set main/. Gradle erwartet beispielsweise, dass Kotlin- oder Java-Klassendateien, die für den Build-Typ „debug“ spezifisch sind, sich in den Verzeichnissen src/debug/kotlin/ oder src/debug/java/ befinden.
Das Android Gradle-Plug-in bietet eine nützliche Gradle-Aufgabe, die zeigt, wie Sie Ihre Dateien für die einzelnen Build-Typen, Produktvarianten und Build-Varianten organisieren. Das folgende Beispiel aus der Aufgabenausgabe beschreibt, wo Gradle bestimmte Dateien für den Build-Typ „debug“ erwartet:
------------------------------------------------------------ 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 Toolfensterleiste auf Gradle.
Gehen Sie zu MyApplication > Tasks > android und doppelklicken Sie auf sourceSets.
Damit der Ordner Tasks angezeigt wird, muss Gradle die Aufgabenliste während der Synchronisierung erstellen. 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 der Gradle-Synchronisierung nicht erstellen) auf.
- Nachdem Gradle die Aufgabe ausgeführt hat, wird das Fenster Ausführen geöffnet, in dem die Ausgabe angezeigt wird.
Hinweis: In der Ausgabe der Aufgabe wird auch gezeigt, wie Sie Source-Sets für Dateien organisieren, die Sie zum Ausführen von Tests für Ihre App verwenden möchten, z. B. die Test-Source-Sets test/ und androidTest/.
Wenn Sie eine neue Build-Variante erstellen, erstellt Android Studio die Source-Set-Verzeichnisse nicht für Sie, bietet Ihnen aber einige Optionen, die Ihnen dabei helfen. So erstellen Sie beispielsweise nur das Verzeichnis java/ für den Build-Typ „debug“:
- Öffnen Sie den Bereich Projekt und wählen Sie im Menü oben im Bereich die Ansicht Projekt aus.
- Rufen Sie
MyProject/app/src/auf. - Rechtsklicken Sie auf das Verzeichnis
srcund 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 Source-Set-Verzeichnis für den Debug-Build-Typ und 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 den Build-Typ „debug“:
- Klicke im Bereich Projekt mit der rechten Maustaste auf das Verzeichnis
srcund wähle Neu > XML > Values XML File 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 (Ziel-Source-Set) die Option debug aus.
- Klicken Sie auf Fertig.
Da der Build-Typ „debug“ als Ziel-Source-Set angegeben wurde, erstellt Android Studio beim Erstellen der XML-Datei automatisch die erforderlichen Verzeichnisse. Die resultierende Verzeichnisstruktur sieht wie in Abbildung 1 aus.
Abbildung 1. Neue Source-Set-Verzeichnisse für den Build-Typ „debug“.
Aktive Quellensätze haben einen grünen Indikator in ihrem Symbol, der anzeigt, dass sie aktiv sind. Das Source-Set debug hat das Suffix [main], um anzuzeigen, dass es mit dem Source-Set main zusammengeführt wird.
Mit demselben Verfahren können Sie auch Source-Set-Verzeichnisse für Produktvarianten wie src/demo/ und Build-Varianten wie src/demoDebug/ erstellen. Darüber hinaus können Sie Test-Source-Sets erstellen, die auf bestimmte Build-Varianten wie src/androidTestDemoDebug/ ausgerichtet sind. Weitere Informationen findest du unter Source-Sets testen.
Standardkonfigurationen für Source-Sets ändern
Wenn Sie Quellen haben, die nicht in der Standard-Source-Set-Dateistruktur organisiert sind, die Gradle erwartet, wie im vorherigen Abschnitt zum Erstellen von Source-Sets beschrieben, können Sie den Block
sourceSets verwenden, um zu ändern, wo Gradle nach Dateien für jede Komponente eines Source-Sets sucht.
Der Block sourceSets muss sich im Block android befinden. Sie müssen die Quelldateien nicht verschieben. Sie müssen Gradle nur die Pfade relativ zur build.gradle.kts-Datei auf Modulebene angeben, unter denen Gradle Dateien für jede Source-Set-Komponente finden kann. In der API-Referenz für das Android-Gradle-Plug-in erfahren Sie, welche Komponenten Sie konfigurieren können und ob Sie sie mehreren Dateien oder Verzeichnissen zuordnen können.
Im folgenden Codebeispiel werden Quellen aus dem Verzeichnis app/other/ bestimmten Komponenten des Source-Sets main zugeordnet und das Stammverzeichnis des Source-Sets androidTest wird 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") ... } } ...
Groovy
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' ... } } } ...
Ein Quellverzeichnis kann nur zu einem Source-Set gehören. Sie können beispielsweise nicht dieselben Testquellen für die Quellensätze test und androidTest freigeben. Das liegt daran, dass Android Studio für jedes Source-Set separate IntelliJ-Module erstellt und keine doppelten Inhaltsstämme in verschiedenen Source-Sets unterstützt.
Mit Source-Sets erstellen
In Source-Set-Verzeichnissen können Sie den Code und die Ressourcen speichern, die nur mit bestimmten Konfigurationen verpackt werden sollen. Wenn ihr beispielsweise die Build-Variante „demoDebug“ erstellt, die das Kreuzprodukt der Produktvariante „demo“ und des Build-Typs „debug“ ist, prüft Gradle diese Verzeichnisse und weist ihnen die folgende Priorität zu:
-
src/demoDebug/(Source-Set der Build-Variante) -
src/debug/(Build-Typ-Source-Set) -
src/demo/(Source-Set für Produktvariante) -
src/main/(Haupt-Source-Set)
Source-Sets, die für Kombinationen von Produktvarianten erstellt werden, müssen alle Flavor-Dimensionen enthalten. Das Source-Set 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 Produktvarianten kombinieren, wird die Priorität zwischen den Produktvarianten durch die Flavor-Dimension bestimmt, zu der sie gehören. Wenn Sie Flavor-Dimensionen mit der Property
android.flavorDimensions auflisten, werden Produktvarianten in der Reihenfolge priorisiert, in der ihre Dimensionen deklariert werden. Dabei haben frühere Dimensionen Vorrang vor nachfolgenden. Außerdem haben Source-Sets, die Sie für Kombinationen von Produktvarianten erstellen, eine höhere Priorität als Source-Sets, die zu einer einzelnen Produktvariante gehören.
Die Prioritätsreihenfolge bestimmt, welches Source-Set eine höhere Priorität hat, wenn Gradle Code und Ressourcen kombiniert. Da das Verzeichnis des Source-Sets demoDebug/ wahrscheinlich Dateien enthält, die für diese Build-Variante spezifisch sind, verwendet Gradle die Datei im Source-Set demoDebug/, wenn demoDebug/ eine Datei enthält, die auch in debug/ definiert ist. Ebenso gibt Gradle Dateien in den Source-Sets für Build-Typ und Produktvariante eine höhere Priorität als denselben Dateien in main/.
Gradle berücksichtigt diese Prioritätsreihenfolge, wenn die folgenden Build-Regeln angewendet werden:
- Der gesamte Quellcode in den Verzeichnissen
kotlin/oderjava/wird zusammen kompiliert, um eine einzelne Ausgabe zu generieren.Hinweis: Bei einer bestimmten Build-Variante gibt Gradle einen Build-Fehler aus, wenn zwei oder mehr Source-Set-Verzeichnisse dieselbe Kotlin- oder Java-Klasse definieren. Wenn Sie beispielsweise eine Debug-App erstellen, können Sie nicht sowohl
src/debug/Utility.ktals auchsrc/main/Utility.ktdefinieren, da Gradle während des Build-Prozesses beide Verzeichnisse prüft und einen Fehler „Doppelte Klasse“ ausgibt. Wenn Sie verschiedene Versionen vonUtility.ktfür unterschiedliche Build-Typen verwenden möchten, muss jeder Build-Typ eine eigene Version der Datei definieren und darf sie nicht in das Source-Setmain/aufnehmen. - Manifeste werden zu einem einzigen Manifest zusammengeführt. Die Priorität wird in derselben Reihenfolge wie in der Liste im vorherigen Beispiel vergeben. Beispielsweise überschreiben die Manifesteinstellungen für einen Build-Typ die Manifesteinstellungen für eine Produktvariante. 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 vergeben. Beispielsweise überschreiben Werte, die in einer Datei im Source-Set des Build-Typs definiert sind, die Werte, die in derselben Datei in einer Produktvariante definiert sind. - Ressourcen in den Verzeichnissen
res/undasset/werden zusammen verpackt. Wenn Ressourcen mit demselben Namen in zwei oder mehr Source-Sets definiert sind, wird die Priorität in derselben Reihenfolge wie in der Liste im vorherigen Beispiel vergeben. - Gradle weist Ressourcen und Manifesten, die in Abhängigkeiten von Bibliotheksmodulen enthalten sind, beim Erstellen der App die niedrigste Priorität zu.
Abhängigkeiten deklarieren
Wenn Sie eine Abhängigkeit für eine bestimmte Build-Variante oder ein Test-Source-Set konfigurieren möchten, stellen Sie dem Namen der Build-Variante oder des Test-Source-Sets das Schlüsselwort Implementation voran, wie im folgenden Beispiel gezeigt:
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.6.1") }
Groovy
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.6.1' }
Weitere Informationen zum Konfigurieren von Abhängigkeiten finden Sie unter Build-Abhängigkeiten hinzufügen.
Variantenabhängige Abhängigkeitsverwaltung verwenden
Das Android-Gradle-Plug-in 3.0.0 und höher enthält einen neuen Abhängigkeitsmechanismus, der Varianten bei der Verwendung einer Bibliothek automatisch abgleicht. Beispielsweise verwendet die debug-Variante einer App automatisch die debug-Variante einer Bibliothek. Das funktioniert auch bei der 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 passende Fallbacks bereitstellen, wie im folgenden Abschnitt beschrieben, falls ein direkter Abgleich nicht möglich ist.
Angenommen, in Ihrer App wird ein Build-Typ namens „Staging“ konfiguriert, aber in einer der Bibliotheksabhängigkeiten nicht. Wenn das Plug-in versucht, die „Staging“-Version Ihrer App zu erstellen, weiß es nicht, welche Version der Bibliothek verwendet werden soll. Sie erhalten dann eine Fehlermeldung ähnlich der folgenden:
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 auflöst, 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 variantenabhängigen Abgleich von Abhängigkeiten und wie Sie diese mithilfe von DSL-Attributen beheben können:
Ihre App enthält einen Build-Typ, der in einer Bibliotheksabhängigkeit nicht vorhanden ist.
Ihre App enthält beispielsweise den Build-Typ „Staging“, eine Abhängigkeit enthält jedoch nur die Build-Typen „Debug“ und „Release“.
Es gibt kein Problem, wenn eine Bibliotheksabhängigkeit einen Build-Typ enthält, den Ihre App nicht hat. Das liegt daran, dass das Plug-in diesen Build-Typ nie von 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") } } }
Groovy
// 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 Ihre App Flavors, die in der Bibliothek nicht vorhanden sind.
Beispiel: Sowohl Ihre App als auch ihre Bibliotheksabhängigkeiten enthalten eine Flavor-Dimension „tier“. Die Dimension „tier“ in der App enthält jedoch die Varianten „free“ und „paid“, während eine Abhängigkeit nur die Varianten „demo“ und „paid“ für dieselbe Dimension enthält.
Wenn eine bestimmte Flavor-Dimension sowohl in der App als auch in ihren Bibliotheksabhängigkeiten vorhanden ist, ist es kein Problem, wenn eine Bibliothek eine Produktvariante enthält, die in Ihrer App nicht vorhanden ist. Das liegt daran, dass das Plug-in diese Variante nie von der Abhängigkeit anfordert.
Verwenden Sie
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") } } }
Groovy
// 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 enthält eine Flavor-Dimension, die Ihre App nicht enthält.
Eine Bibliotheksabhängigkeit enthält beispielsweise Varianten für eine „minApi“-Dimension, Ihre App enthält jedoch nur Varianten für die „tier“-Dimension. Wenn Sie die „freeDebug“-Version Ihrer App erstellen möchten, weiß das Plug-in nicht, ob es die „minApi23Debug“- oder die „minApi18Debug“-Version der Abhängigkeit verwenden soll.
Es gibt kein Problem, wenn Ihre App eine Flavor-Dimension enthält, die eine Bibliotheksabhängigkeit nicht enthält. Das liegt daran, dass das Plug-in nur Varianten der Dimensionen abgleicht, die in der Abhängigkeit vorhanden sind. Wenn eine Abhängigkeit beispielsweise keine Dimension für ABIs enthält, wird für die „freeX86Debug“-Version Ihrer App die „freeDebug“-Version der Abhängigkeit verwendet.
Verwenden Sie
missingDimensionStrategyim BlockdefaultConfig, um die Standardvariante für das Plug-in anzugeben, die aus jeder fehlenden Dimension ausgewählt werden soll, wie im folgenden Beispiel gezeigt. Sie können Ihre Auswahl auch im BlockproductFlavorsüberschreiben, sodass für jede Variante eine andere Abgleichstrategie für eine fehlende Dimension angegeben werden kann.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") {} } }
Groovy
// 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.
Signierungseinstellungen konfigurieren
Gradle signiert das APK oder AAB Ihres Release-Builds nur, wenn Sie explizit eine Signaturkonfiguration für diesen Build definieren. Wenn Sie noch keinen Signaturschlüssel haben, generieren Sie einen Uploadschlüssel und einen Schlüsselspeicher mit Android Studio.
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. Du musst deinen Schlüsselspeicher an einem sicheren Ort aufbewahren.
- Erstellen Sie einen privaten Schlüssel. Ein privater Schlüssel wird verwendet, um Ihre App für die Bereitstellung zu signieren. Er ist nie in der App enthalten und wird nicht an unbefugte Dritte weitergegeben.
-
Fügen Sie die Signaturkonfiguration der Datei
build.gradle.ktsauf Modulebene hinzu:Kotlin
... android { ... defaultConfig {...} signingConfigs { create("release") { storeFile = file("myreleasekey.keystore") storePassword = "password" keyAlias = "MyReleaseKey" keyPassword = "password" } } buildTypes { getByName("release") { ... signingConfig = signingConfigs.getByName("release") } } }
Groovy
... android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } } }
Hinweis:Es ist nicht empfehlenswert, die Passwörter für den Releaseschlüssel und den Schlüsselspeicher in die Build-Datei aufzunehmen. Konfigurieren Sie stattdessen die Build-Datei so, dass diese Passwörter aus Umgebungsvariablen abgerufen werden, oder lassen Sie sich vom Build-Prozess zur Eingabe dieser Passwörter auffordern.
So rufen Sie diese Passwörter aus Umgebungsvariablen ab:
Kotlin
storePassword = System.getenv("KSTOREPWD") keyPassword = System.getenv("KEYPWD")
Groovy
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.
Nachdem du diesen Vorgang abgeschlossen hast, kannst du deine App bei Google Play veröffentlichen.
Warnung:Bewahren Sie Ihren Schlüsselspeicher und Ihren privaten Schlüssel an einem sicheren Ort auf und erstellen Sie sichere Back-ups. Wenn Sie die Play App-Signatur verwenden und Ihren Uploadschlüssel verlieren, können Sie in der Play Console beantragen, dass er zurückgesetzt wird. Wenn Sie eine App ohne Play App-Signatur veröffentlichen (für Apps, die vor August 2021 erstellt wurden) und Ihren App-Signaturschlüssel verlieren, können Sie keine Updates für Ihre App veröffentlichen, da Sie alle Versionen Ihrer App immer mit demselben Schlüssel signieren müssen.
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.