Build-Varianten konfigurieren

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 Buildvariante steht für eine andere Version Ihrer App, die Sie erstellen können. Sie können beispielsweise eine kostenlose Version Ihrer App mit begrenzten Inhalten und eine kostenpflichtige Version mit mehr Inhalten erstellen. Sie können auch verschiedene Versionen Ihrer App erstellen, die auf verschiedene Geräte ausgerichtet sind, je nach API-Level oder anderen Gerätevarianten.

Buildvarianten sind das Ergebnis von Gradle, das mithilfe einer bestimmten Reihe von Regeln Einstellungen, Code und Ressourcen kombiniert, die in Ihren Buildtypen und Produktvarianten konfiguriert sind. 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.

Buildtypen konfigurieren

Sie können Buildtypen im Block android der build.gradle.kts-Datei auf Modulebene erstellen und konfigurieren. Wenn Sie ein neues Modul erstellen, werden in Android Studio automatisch die Buildtypen „Debug“ und „Release“ erstellt. Der Debug-Buildtyp wird zwar nicht in der Build-Konfigurationsdatei angezeigt, aber in Android Studio mit debuggable true konfiguriert. So können Sie die App auf sicheren Android-Geräten debuggen und die App-Signatur mit einem generischen Debug-Schlüsselspeicher konfigurieren.

Sie können den Buildtyp „Fehlerbehebung“ Ihrer Konfiguration hinzufügen, wenn Sie bestimmte Einstellungen hinzufügen oder ändern möchten. Im folgenden Beispiel wird ein applicationIdSuffix für den Debug-Buildtyp angegeben und ein Buildtyp vom Typ „Staging“ konfiguriert, der mit den Einstellungen aus dem Debug-Buildtyp 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. Wenn Sie Ihr Projekt synchronisieren möchten, klicken Sie in der Benachrichtigungsleiste, die nach einer Änderung angezeigt wird, auf Jetzt synchronisieren oder in der Symbolleiste auf Projekt synchronisieren . Wenn Android Studio Fehler in Ihrer Konfiguration erkennt, wird das Fenster Nachrichten mit einer Beschreibung des Problems angezeigt.

Weitere Informationen zu allen Properties, die Sie mit Buildtypen konfigurieren können, finden Sie in der BuildType-Referenz.

Produktvarianten konfigurieren

Das Erstellen von Produktvarianten ähnelt dem Erstellen von Buildtypen. Fügen Sie dem Block productFlavors in Ihrer Build-Konfiguration Produktvarianten hinzu und geben Sie die gewünschten Einstellungen an. Die Produktvarianten unterstützen dieselben Properties wie defaultConfig, da defaultConfig zur Klasse ProductFlavor gehört. Dies 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 App-ID

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 relative Aktivitäten oder Dienstregistrierungen aufzulösen. So kannst du mit applicationId jedem Produktvariante eine eindeutige ID für die Verpackung und den Vertrieb zuweisen, ohne den Quellcode ändern zu müssen.

Alle Geschmacksrichtungen müssen zu einer benannten Geschmacksdimension gehören, also einer Gruppe von Produktgeschmacksrichtungen. 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 Flavors des Moduls zu.

Im folgenden Codebeispiel wird eine Variante mit dem Namen „version“ erstellt und die Produktvarianten „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"
        }
    }
}

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 (vor August 2021 erstellt) haben, die Sie über APKs bei Google Play vertreiben, und Ihre App mit der Unterstützung für mehrere APKs bei Google Play vertreiben möchten, weisen Sie allen Varianten denselben applicationId-Wert zu und geben Sie jeder Variante einen anderen versionCode-Wert. Wenn Sie unterschiedliche Varianten Ihrer App als separate Apps bei Google Play anbieten möchten, müssen Sie jeder Variante eine andere applicationId zuweisen.

Nachdem Sie die Produktvarianten erstellt und konfiguriert haben, klicken Sie in der Benachrichtigungsleiste auf Jetzt synchronisieren. Nach Abschluss der Synchronisierung erstellt Gradle automatisch Buildvarianten basierend auf Ihren Buildtypen und Produktvarianten und benennt sie gemäß <product-flavor><Build-Type>. Wenn Sie beispielsweise die Produktvarianten „demo“ und „full“ erstellt und die Standard-Buildtypen „debug“ und „release“ beibehalten haben, erstellt Gradle die folgenden Buildvarianten:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

Wenn Sie auswählen möchten, welche Buildvariante erstellt und ausgeführt werden soll, klicken Sie auf Build > Buildvariante auswählen und wählen Sie im Menü eine Buildvariante aus. Wenn Sie jede Buildvariante mit eigenen Funktionen und Ressourcen anpassen möchten, müssen Sie Quell-Sets erstellen und verwalten, wie auf dieser Seite beschrieben.

Anwendungs-ID für Buildvarianten ändern

Wenn Sie ein APK oder AAB für Ihre App erstellen, taggen die Build-Tools die App mit der Anwendungs-ID, die im Block defaultConfig der Datei build.gradle.kts definiert ist, wie im folgenden Beispiel gezeigt. Wenn Sie jedoch verschiedene Versionen Ihrer App erstellen möchten, die als separate Einträge im Google Play Store erscheinen, z. B. eine kostenlose und eine Pro-Version, müssen Sie separate Buildvarianten mit jeweils einer anderen Anwendungs-ID erstellen.

Definieren Sie in diesem Fall jede Buildvariante als separate Produktvariante. 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"
        }
    }
}

Groovy

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".

Mit applicationIdSuffix können Sie auch ein Segment anhängen, das auf Ihrem Build-Typ basiert. Hier ein Beispiel:

Kotlin

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

Groovy

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

Da Gradle die Buildtypkonfiguration nach dem Produkt-Flavor anwendet, lautet die Anwendungs-ID für die Buildvariante „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 (vor August 2021 erstellt) haben, die Sie über APKs bei Google Play vertreiben, und mit demselben App-Eintrag mehrere APKs bereitstellen möchten, die jeweils auf eine andere Gerätekonfiguration ausgerichtet sind, z. B. auf die API-Ebene, müssen Sie für jede Buildvariante dieselbe Anwendungs-ID verwenden, aber jedem APK eine andere versionCode zuweisen. Weitere Informationen finden Sie unter Unterstützung für mehrere APKs. Die Veröffentlichung mit AABs ist davon nicht betroffen, da dabei ein einzelnes Artefakt mit einem einzelnen Versionscode und einer einzigen Anwendungs-ID verwendet wird.

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 Buildvariablen in das Manifest einfügen.

Mehrere Produktvarianten mit Variantendimensionen kombinieren

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 Produktvarianten als Variantendimensionen erstellen.

Beim Erstellen Ihrer App kombiniert Gradle eine Produktvariantenkonfiguration aus jeder von Ihnen definierten Variantendimension mit einer Buildtypkonfiguration, um die endgültige Buildvariante 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 einer 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 Buildvarianten entspricht dem Produkt aus der Anzahl der Flavors in jeder Flavor-Dimension und der Anzahl der konfigurierten Buildtypen. Wenn Gradle die einzelnen Buildvarianten oder entsprechenden Artefakte benennt, werden zuerst Produktvarianten mit einer höheren Prioritätsdimension angezeigt, gefolgt von denen mit niedrigeren Prioritätsdimensionen und dann vom Buildtyp.

Anhand der vorherigen Build-Konfiguration erstellt Gradle insgesamt zwölf Buildvarianten mit dem folgenden Benennungsschema:

  • Build-Variante: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • Entsprechendes APK: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • Beispiel:
    Buildvariante: 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 im Verzeichnis src/demoMinApi24/java/ erstellen und hinzufügen. Gradle verwendet diese Quellen dann nur, wenn eine Variante erstellt wird, die diese beiden Produktvarianten kombiniert.

Quell-Sets, die Sie für Produkt-Flavor-Kombinationen 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 Produktvarianten und Build-Typen. Es kann jedoch bestimmte Buildvarianten geben, die Sie nicht benötigen oder die im Kontext Ihres Projekts keinen Sinn ergeben. Wenn Sie bestimmte Konfigurationen von Buildvarianten entfernen möchten, erstellen Sie einen Variantenfilter in der build.gradle.kts-Datei auf Modulebene.

Angenommen, Sie möchten für die Demoversion der App nur API-Ebenen 23 und höher unterstützen. Mit dem Block variantFilter können Sie alle Konfigurationen für Buildvarianten herausfiltern, 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 Symbolleiste des Toolfensters auf Build-Varianten klicken.

Quellsätze erstellen

Standardmäßig erstellt Android Studio den Quellsatz main/ 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 festzulegen, welche Dateien Gradle für bestimmte Buildtypen, Produktvarianten, Kombinationen von Produktvarianten (bei Verwendung von Variantendimensionen) und Buildvarianten kompiliert und verpackt.

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 Quelldateien und ‑verzeichnisse ähnlich wie das main/-Quellset organisiert sind. Beispielsweise erwartet Gradle, dass sich Kotlin- oder Java-Klassendateien, die für den Buildtyp „debug“ spezifisch sind, in den Verzeichnissen 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, Produktvarianten und Build-Varianten organisieren. Im folgenden Beispiel aus der Aufgabenausgabe wird beispielsweise beschrieben, 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:

  1. Klicken Sie in der Leiste des Toolfensters auf Gradle.
  2. Gehen Sie zu Meine Anwendung > Aufgaben > android und doppelklicken Sie auf sourceSets.

    Damit der Ordner Tasks angezeigt wird, müssen Sie Gradle die Aufgabenliste während der Synchronisierung erstellen lassen. Führen Sie dazu die folgenden Schritte aus:

    1. Klicken Sie auf Datei > Einstellungen > Experimentell (Android Studio > Einstellungen > Experimentell unter macOS).
    2. Heben Sie die Auswahl der Option Gradle-Aufgabenliste während der Gradle-Synchronisierung nicht erstellen auf.
  3. Nachdem Gradle die Aufgabe ausgeführt hat, wird das Fenster Ausführen geöffnet, in dem die Ausgabe angezeigt wird.

Hinweis:In der Aufgabenausgabe wird auch gezeigt, wie Sie Quellsätze für Dateien organisieren, mit denen Sie Tests für Ihre App ausführen möchten, z. B. die Testquellensätzetest/ und androidTest/.

Wenn Sie eine neue Build-Variante erstellen, erstellt Android Studio die Verzeichnisse für das Quellset nicht für Sie. Es bietet Ihnen jedoch einige Optionen, die Ihnen dabei helfen können. So erstellen Sie beispielsweise nur das Verzeichnis java/ für Ihren Build-Typ „debug“:

  1. Öffnen Sie den Bereich Projekt und wählen Sie oben im Menü die Ansicht Projekt aus.
  2. Zu MyProject/app/src/ navigieren
  3. Klicken Sie mit der rechten Maustaste auf das Verzeichnis src und wählen Sie Neu > Verzeichnis aus.
  4. Wählen Sie im Menü unter Gradle-Quellsätze die Option full/java aus.
  5. Drücken Sie die Eingabetaste.

Android Studio erstellt ein Quellsatzverzeichnis für Ihren Debug-Build-Typ und erstellt dann darin das Verzeichnis java/. Alternativ können Sie die Verzeichnisse auch in Android Studio erstellen, wenn Sie Ihrem Projekt eine neue Datei für eine bestimmte Build-Variante hinzufügen.

So erstellen Sie beispielsweise eine Werte-XML-Datei für den Buildtyp „debug“:

  1. Klicken Sie im Bereich Projekt mit der rechten Maustaste auf das Verzeichnis src und wählen Sie Neu > XML > XML-Datei mit Werten aus.
  2. Geben Sie den Namen für die XML-Datei ein oder belassen Sie den Standardnamen.
  3. Wählen Sie im Menü neben Zielquellen-Set die Option debug aus.
  4. 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 dann so aus wie in Abbildung 1.

Abbildung 1: Neue Quellsatzverzeichnisse für den Build-Typ „debug“.

Aktive Quellengruppen sind durch ein grünes Symbol gekennzeichnet. Das debug-Quellset hat das Suffix [main], um anzuzeigen, dass es mit dem main-Quellsatz zusammengeführt wird.

Mit demselben Verfahren können Sie auch Verzeichnisse für Quellsätze für Produktvarianten 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 für Quellgruppen ändern

Wenn Ihre Quellen nicht in der von Gradle erwarteten Standarddateistruktur des Quellsatzes organisiert sind, wie im vorherigen Abschnitt zum Erstellen von Quellsätzen beschrieben, können Sie mit dem Block sourceSets ändern, wo Gradle nach Dateien für die einzelnen Komponenten eines Quellsatzes sucht.

Der Block sourceSets muss sich im Block android 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")
      ...
  }
}
...

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 Quellsatz gehören. 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:

  1. src/demoDebug/ (Build-Variante – Quellsatz)
  2. src/debug/ (Build-Typ-Quellsatz)
  3. src/demo/ (Quellsatz für Produktvariante)
  4. src/main/ (Hauptquellensatz)

In Quellgruppen, die für Kombinationen von Produktvarianten erstellt wurden, müssen alle Variantendimensionen enthalten sein. 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 Variantendimensionen abdecken, wird nicht unterstützt.

Wenn Sie mehrere Geschmacksrichtungen kombinieren, wird die Priorität der Geschmacksrichtungen 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. 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, welche Quellgruppe beim Kombinieren von Code und Ressourcen eine höhere Priorität hat. Da das Verzeichnis „demoDebug/“ wahrscheinlich Dateien enthält, die für diese Buildvariante spezifisch sind, verwendet Gradle die Datei im Quellsatz „demoDebug/“, wenn „demoDebug/“ eine Datei enthält, die auch in „debug/“ definiert ist. Ebenso ordnet Gradle Dateien in den Build-Typen und Produktvarianten-Quelldateien eine höhere Priorität zu 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/ oder java/ 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 Quellsatz-Verzeichnisse gefunden werden, in denen dieselbe Kotlin- oder Java-Klasse definiert ist. Wenn Sie beispielsweise eine Debug-App erstellen, können Sie weder src/debug/Utility.kt noch src/main/Utility.kt definieren, da Gradle während des Build-Prozesses beide Verzeichnisse überprüft und einen Fehler vom Typ „Duplizierte Klasse“ auslöst. Wenn Sie unterschiedliche Versionen von Utility.kt für verschiedene Buildtypen benötigen, muss für jeden Buildtyp eine eigene Version der Datei definiert werden. Sie darf nicht in der main/-Quellgruppe enthalten sein.

  • 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. zwei strings.xml-Dateien, wird die Priorität in der Reihenfolge wie in der Liste im vorherigen Beispiel vergeben. Das heißt, Werte, die in einer Datei im Quellsatz des Buildtyps definiert sind, überschreiben die Werte, die in derselben Datei in einer Produktvariante definiert sind, usw.
  • Ressourcen in den Verzeichnissen res/ und asset/ werden zusammen verpackt. Wenn in zwei oder mehr Quellsätzen Ressourcen mit demselben Namen definiert sind, wird die Priorität in der Reihenfolge der Liste im vorherigen Beispiel vergeben.
  • Gradle ordnet Ressourcen und Manifeste, die in Bibliotheksmodulabhängigkeiten 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 einen Testquellensatz konfigurieren möchten, stellen Sie den Namen der Build-Variante oder des Testquellensatzes vor dem Schlüsselwort Implementation vor, 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.

Variantenspezifische Abhängigkeitsverwaltung verwenden

Das Android Gradle-Plug-in 3.0.0 und höher enthält einen neuen Abhängigkeitsmechanismus, der beim Verwenden einer Bibliothek automatisch Varianten abgleicht. 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 korrekt abgleichen kann, müssen Sie wie im folgenden Abschnitt beschrieben entsprechende Fallbacks angeben, falls keine direkte Übereinstimmung möglich ist.

Angenommen, Sie konfigurieren in Ihrer App einen Build-Typ namens „Staging“, aber eine ihrer 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 der Variantenabgleichung beheben

Das Plug-in enthält DSL-Elemente, mit denen Sie steuern können, wie Gradle Situationen löst, in denen eine direkte Übereinstimmung zwischen einer App und einer Abhängigkeit nicht möglich ist.

Im Folgenden finden Sie eine Liste von Problemen im Zusammenhang mit der variantenspezifischen Abhängigkeitsabgleichung und wie Sie diese mithilfe von DSL-Properties beheben 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“.

    Es liegt kein Problem vor, wenn eine Bibliothek abhängig von einem Buildtyp ist, den Ihre App nicht hat. Das liegt daran, dass das Plug-in diesen Buildtyp nie von der Abhängigkeit anfordert.

    Verwenden Sie matchingFallbacks, um alternative Übereinstimmungen für einen bestimmten Buildtyp 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 Variante, die sowohl in der App als auch in der Bibliotheksabhängigkeit vorhanden ist, enthält Ihre App Varianten, die in der Bibliothek nicht vorhanden sind.

    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.

    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 die Dimension „minApi“, Ihre App jedoch nur Varianten für die Dimension „Tier“. Wenn Sie die Version „freeDebug“ Ihrer App erstellen möchten, weiß das Plug-in nicht, ob die Version „minApi23Debug“ oder „minApi18Debug“ der Abhängigkeit verwendet werden soll.

    Es gibt kein Problem, wenn Ihre App eine Variante enthält, die eine Bibliothekabhängigkeit nicht hat. Das liegt daran, dass das Plug-in nur die Varianten der Dimensionen abgleicht, die in der Abhängigkeit vorhanden sind. Wenn eine Abhängigkeit beispielsweise keine Dimension für ABIs enthält, wird in der Version „freeX86Debug“ Ihrer App die Version „freeDebug“ der Abhängigkeit verwendet.

    Verwenden Sie missingDimensionStrategy im Block defaultConfig, um den Standard-Flavor für das Plug-in anzugeben, der aus jeder fehlenden Dimension ausgewählt werden soll, wie im folgenden Beispiel gezeigt. Sie können Ihre Auswahl im Block productFlavors auch überschreiben, damit jede Variante eine andere Abgleichsstrategie für eine fehlende Dimension angeben 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.

Signatureinstellungen 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 Keystore mit Android Studio.

So konfigurieren Sie die Signaturkonfigurationen für Ihren Release-Buildtyp manuell mit Gradle-Buildkonfigurationen:

  1. 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.
  2. Erstellen Sie einen privaten Schlüssel. Mit einem privaten Schlüssel wird Ihre App für den Vertrieb signiert. Er ist niemals in der App enthalten und wird nicht an unbefugte Dritte weitergegeben.
  3. 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")
            }
        }
    }

    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 Release-Schlü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 während des Build-Prozesses nach diesen Passwörtern fragen.

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 Eigenschaftendatei laden. Fügen Sie diese Datei aus Sicherheitsgründen nicht der Versionskontrolle hinzu. Richten Sie es stattdessen lokal für jeden Entwickler ein. Weitere Informationen finden Sie im Hilfeartikel Unterzeichnungsinformationen aus Ihren Build-Dateien entfernen.

Danach können Sie Ihre App vertreiben und bei Google Play veröffentlichen.

Warnung:Bewahren Sie den Schlüsselspeicher und den privaten Schlüssel an einem sicheren Ort auf und sorgen Sie für 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

Beim Veröffentlichen von Wear OS-Apps 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.