Questa pagina mostra come configurare le varianti di build per creare versioni diverse dell'app da un singolo progetto e come gestire correttamente le dipendenze e le configurazioni di firma.
Ogni variante di build rappresenta una versione diversa dell'app che puoi compilare. Ad esempio, potresti creare una versione della tua app senza costi con un insieme limitato di contenuti e un'altra a pagamento che ne includa di più. Puoi anche creare versioni diverse della tua app che hanno come target dispositivi diversi, in base al livello API o ad altre varianti del dispositivo.
Le varianti di build sono il risultato dell'utilizzo da parte di Gradle di un insieme specifico di regole per combinare impostazioni, codice e risorse configurati nei tipi di build e nei gusti dei prodotti. Anche se non configuri direttamente le varianti di build, configuri i tipi di build e le versioni del prodotto che le formano.
Ad esempio, un flavor del prodotto "demo" potrebbe specificare determinate funzionalità e requisiti del dispositivo, come codice sorgente personalizzato, risorse e livelli API minimi, mentre il tipo di build "debug" applica impostazioni di compilazione e pacchettistica diverse, come opzioni di debug e chiavi di firma. La variante di compilazione che combina queste due è la versione "demoDebug" dell'app e include una combinazione delle configurazioni e delle risorse incluse nel flavor del prodotto "demo", nel tipo di compilazione "debug" e nel set di origine main/
.
Configurare i tipi di build
Puoi creare e configurare i tipi di build all'interno del blocco android
del file build.gradle.kts
a livello di modulo. Quando crei un nuovo modulo, Android Studio crea automaticamente i tipi di build di debug e release. Sebbene il tipo di build di debug non venga visualizzato nel file di configurazione della build, Android Studio lo configura con debuggable
true
. In questo modo puoi eseguire il debug dell'app su dispositivi Android sicuri e configurare la firma dell'app con un keystore di debug generico.
Puoi aggiungere il tipo di build di debug alla configurazione se vuoi aggiungere o modificare determinate impostazioni. Il seguente esempio specifica un
applicationIdSuffix
per il tipo di compilazione di debug e configura un tipo di compilazione "staging" che viene inizializzato utilizzando le impostazioni del tipo di compilazione di debug:
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" } } }
Nota:quando apporti modifiche a un file di configurazione di compilazione, Android Studio richiede di sincronizzare il progetto con la nuova configurazione. Per sincronizzare il progetto, fai clic su Sincronizza ora nella barra delle notifiche che viene visualizzata quando apporti una modifica oppure fai clic su Sincronizza progetto nella barra degli strumenti. Se Android Studio rileva errori nella configurazione, viene visualizzata la finestra Messaggi per descrivere il problema.
Per scoprire di più su tutte le proprietà che puoi configurare con i tipi di build,
leggi la documentazione di riferimento di
BuildType
.
Configurare le versioni dei prodotti
La creazione di varianti del prodotto è simile alla creazione di tipi di build. Aggiungi le varianti del prodotto al
productFlavors
blocco nella configurazione di compilazione e includi le impostazioni che preferisci.
Le varianti del prodotto supportano le stesse proprietà di defaultConfig
, perché defaultConfig
appartiene in realtà alla classe
ProductFlavor
. Ciò significa che puoi fornire la configurazione di base per tutti i tipi nel blocco defaultConfig
e ogni tipo può modificare uno di questi valori predefiniti, ad esempio applicationId
. Per approfondire l'ID applicazione, consulta Impostare l'ID applicazione.
Nota:devi comunque specificare un nome del pacchetto utilizzando l'attributo package
nel file manifest main/
. Devi anche utilizzare questo
nome del pacchetto nel codice sorgente per fare riferimento alla classe R
o per risolvere eventuali
registrazioni di attività o servizi correlati. In questo modo puoi utilizzare
applicationId
per assegnare a ogni versione del prodotto un ID univoco per
il packaging e la distribuzione senza dover modificare il codice sorgente.
Tutti i gusti devono appartenere a una dimensione del gusto denominata, ovvero un gruppo di gusti del prodotto. Devi assegnare tutti i gusti a una dimensione del gusto. In caso contrario, verrà visualizzato il seguente errore di compilazione.
Error: All flavors must now belong to a named flavor dimension. The flavor 'flavor_name' is not assigned to a flavor dimension.
Se un determinato modulo specifica solo una dimensione del gusto, il plug-in Gradle per Android assegna automaticamente tutti i gusti del modulo a quella dimensione.
Il seguente esempio di codice crea una dimensione del tipo di prodotto denominata "versione" e aggiunge i tipi di prodotto "demo" e "completo". Questi tipi di analisi forniscono i propri
applicationIdSuffix
e
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" } } }
Nota: se hai un'app precedente (creata prima di agosto 2021) che distribuisci utilizzando gli APK su Google Play, per distribuire la tua app utilizzando il supporto di più APK su Google Play, assegna lo stesso valore applicationId
a tutte le varianti e assegna a ogni variante un versionCode
diverso. Per distribuire diverse varianti della tua app come app separate su Google Play, devi assegnare un applicationId
diverso a ogni variante.
Dopo aver creato e configurato le versioni del prodotto, fai clic su Sincronizza nella barra delle notifiche. Al termine della sincronizzazione, Gradle
crea automaticamente le varianti di build in base ai tipi di build e ai gusti del prodotto
e li nomina in base a
<product-flavor><Build-Type>
. Ad esempio, se hai creato i tipi di prodotto "demo" e "full" e hai mantenuto i tipi di build predefiniti "debug" e "release", Gradle crea le seguenti varianti di build:
-
demoDebug
-
demoRelease
-
fullDebug
-
fullRelease
Per selezionare la variante di build da compilare ed eseguire, vai a Compila > Seleziona variante di build e seleziona una variante di build dal menu. Per iniziare a personalizzare ogni variante di build con le proprie funzionalità e risorse, devi creare e gestire set di origini, come descritto in questa pagina.
Modificare l'ID applicazione per le varianti di build
Quando crei un APK o un AAB per la tua app, gli strumenti di compilazione conteggiano l'app con l'ID applicazione definito nel blocco defaultConfig
del file build.gradle.kts
, come mostrato nell'esempio seguente. Tuttavia, se vuoi creare versioni diverse della tua app da mostrare come schede separate sul Google Play Store, ad esempio una versione "senza costi" e una "pro", devi creare varianti di build distinte con un ID applicazione diverso.
In questo caso, definisci ogni variante di build come sapore del prodotto distinto. Per ogni flavor
all'interno del blocco productFlavors
, puoi ridefinire la proprietà applicationId
oppure puoi aggiungere un segmento all'ID applicazione predefinito
utilizzando applicationIdSuffix
, come mostrato di seguito:
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 questo modo, l'ID applicazione per la versione del prodotto "free" è "com.example.myapp.free".
Puoi anche utilizzare applicationIdSuffix
per aggiungere un segmento in base al tipo di compilazione, come mostrato di seguito:
Kotlin
android { ... buildTypes { getByName("debug") { applicationIdSuffix = ".debug" } } }
Groovy
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
Poiché Gradle applica la configurazione del tipo di build dopo il flavor del prodotto, l'ID applicazione per la variante di build "free debug" è "com.example.myapp.free.debug". Questo è utile quando vuoi avere sia la build di debug sia la build di release sullo stesso dispositivo, perché nessuna delle due app può avere lo stesso ID applicazione.
Se hai un'app precedente (creata prima di agosto 2021) che distribuisci utilizzando gli APK su Google Play e vuoi utilizzare la stessa scheda dell'app per distribuire più APK ognuno dei quali ha come target una configurazione del dispositivo diversa, ad esempio il livello API, devi utilizzare lo stesso ID applicazione per ogni variante di build, ma assegnare a ogni APK unversionCode
diverso. Per ulteriori informazioni, consulta la pagina sul supporto di più APK. La pubblicazione
con gli AAB non è interessata, in quanto utilizza un singolo artefatto che utilizza un singolo
codice versione e ID applicazione per impostazione predefinita.
Suggerimento:se devi fare riferimento all'ID applicazione nel file manifest, puoi utilizzare il segnaposto ${applicationId}
in qualsiasi attributo manifest. Durante una compilazione, Gradle sostituisce questo tag con l'ID applicazione effettivo. Per ulteriori informazioni, consulta la sezione Eseguire l'iniezione di variabili di compilazione nel file manifest.
Combinare più gusti dei prodotti con le dimensioni dei gusti
In alcuni casi, potresti voler combinare le configurazioni di più varianti di prodotto. Ad esempio, potresti voler creare configurazioni diverse per le versioni del prodotto "complete" e "demo" in base al livello dell'API. Per farlo, il plug-in Gradle per Android ti consente di creare più gruppi di varianti di prodotto come dimensioni di varianti.
Durante la compilazione dell'app, Gradle combina una configurazione del gusto del prodotto di ogni dimensione del gusto che definisci, insieme a una configurazione del tipo di build, per creare la variante di build finale. Gradle non combina i sapori dei prodotti che appartengono alla stessa dimensione del sapore.
Il seguente esempio di codice utilizza la proprietà
flavorDimensions
per creare una dimensione del tipo di prodotto "mode" per raggruppare i tipi di prodotto "full" e "demo" e una dimensione del tipo di prodotto "api" per raggruppare le configurazioni dei tipi di prodotto in base al livello dell'API:
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" ... } } } ...
Il numero di varianti di build create da Gradle è uguale al prodotto del numero di varianti in ogni dimensione e del numero di tipi di build configurati. Quando Gradle nomina ogni variante di build o gli elementi corrispondenti, i gusti di prodotto appartenenti alla dimensione del gusto con priorità più alta vengono visualizzati per primi, seguiti da quelli delle dimensioni con priorità inferiore e dal tipo di build.
Utilizzando la configurazione di build precedente come esempio, Gradle crea un totale di 12 varianti di build con il seguente schema di denominazione:
- Variante di compilazione:
[minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
- APK corrispondente:
app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
- Ad esempio,
- Variante di build:
minApi24DemoDebug
- APK corrispondente:
app-minApi24-demo-debug.apk
Oltre alle directory degli insiemi di origine che puoi creare per ogni singolo flavor e variante di build del prodotto, puoi anche creare directory degli insiemi di origine per ogni combinazione di flavor del prodotto. Ad esempio, puoi creare
e aggiungere sorgenti Java alla directory src/demoMinApi24/java/
,
e Gradle utilizza queste sorgenti solo quando crea una variante che combina
questi due tipi di prodotto.
I set di origini che crei per le combinazioni di varianti del prodotto hanno una priorità più alta rispetto ai set di origini che appartengono a ogni singola variante del prodotto. Per scoprire di più sui set di origine e su come Gradle riunisce le risorse, leggi la sezione su come creare set di origine.
Filtrare le varianti
Gradle crea una variante di build per ogni possibile combinazione dei gusti e dei tipi di build del prodotto che configuri. Tuttavia, potrebbero esserci determinate varianti di compilazione di cui non hai bisogno o che non hanno senso nel contesto del tuo progetto. Per rimuovere determinate configurazioni delle varianti di compilazione,
crea un filtro delle varianti nel file build.gradle.kts
a livello di modulo.
Utilizzando la configurazione di build della sezione precedente come esempio,
supponiamo che tu preveda di supportare solo i livelli API 23 e versioni successive per la versione demo
dell'app. Puoi utilizzare il blocco
variantFilter
per filtrare tutte le configurazioni delle varianti di build
che combinano i tipi di prodotto "minApi21" e "demo":
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) } } } ...
Dopo aver aggiunto un filtro delle varianti alla configurazione di compilazione e aver fatto clic su Sincronizza nella barra delle notifiche, Gradle ignora le varianti di compilazione che soddisfano le condizioni specificate. Le varianti di compilazione non vengono più visualizzate nel menu quando fai clic su Compila > Seleziona variante di compilazione nella barra dei menu o su Varianti di compilazione nella barra della finestra dello strumento.
Crea set di origini
Per impostazione predefinita, Android Studio crea il main/
set di origine e le directory per
tutto ciò che vuoi condividere tra tutte le varianti di build. Tuttavia, puoi creare nuovi insiemi di origini per controllare esattamente quali file vengono compilati e pacchettizzati da Gradle per tipi di build, varianti di prodotto e combinazioni di varianti di prodotto specifici (se utilizzi le dimensioni di varianti) e varianti di build.
Ad esempio, puoi definire la funzionalità di base nel set di origine main/
e utilizzare i set di origine del gusto del prodotto per modificare il branding della tua app per clienti diversi oppure includere autorizzazioni speciali e funzionalità di registrazione solo per le varianti di build che utilizzano il tipo di build di debug.
Gradle si aspetta che i file e le directory del set di origine siano organizzati in un determinato modo, in modo simile al set di origine main/
. Ad esempio, Gradle
si aspetta che i file di classe Kotlin o Java specifici per il tipo di build "debug" si trovino
nelle directory src/debug/kotlin/
o src/debug/java/
.
Il plug-in Android per Gradle fornisce un'utile attività Gradle che mostra come organizzare i file per ogni tipo di build, flavor del prodotto e variante di build. Ad esempio, il seguente esempio di output dell'attività descrive dove Gradle si aspetta di trovare determinati file per il tipo di compilazione "debug":
------------------------------------------------------------ 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]
Per visualizzare questo output:
- Fai clic su Gradle nella barra della finestra degli strumenti.
Vai a LaMiaApplicazione > Attività > Android e fai doppio clic su sourceSets.
Per visualizzare la cartella Tasks, devi consentire a Gradle di compilare l'elenco delle attività durante la sincronizzazione. A tale scopo, procedi nel seguente modo:
- Fai clic su File > Impostazioni > Sperimentale (Android Studio > Impostazioni > Sperimentale su macOS).
- Deseleziona Non compilare l'elenco di attività Gradle durante la sincronizzazione di Gradle.
- Dopo che Gradle ha eseguito l'attività, si apre la finestra Esegui per visualizzare l'output.
Nota: l'output dell'attività mostra anche come organizzare i set di origine per i file che vuoi utilizzare per eseguire test per la tua app, ad esempio i set di origine di test test/
e androidTest/
.
Quando crei una nuova variante di build, Android Studio non crea le directory del set di origine per te, ma ti offre alcune opzioni utili. Ad esempio, per creare solo la directory java/
per il tipo di compilazione "debug":
- Apri il riquadro Progetto e seleziona la visualizzazione Progetto dal menu nella parte superiore del riquadro.
- Vai a
MyProject/app/src/
. - Fai clic con il tasto destro del mouse sulla directory
src
e seleziona Nuovo > Directory. - Nel menu sotto Gradle Source Sets (Set di origini Gradle), seleziona full/java.
- Premi Invio.
Android Studio crea una directory del set di origine per il tipo di build di debug e poi crea la directory java/
al suo interno. In alternativa,
Android Studio può creare le directory per te quando aggiungi un nuovo file al
progetto per una variante di build specifica.
Ad esempio, per creare un file XML di valori per il tipo di build "debug":
- Nel riquadro Progetto, fai clic con il tasto destro del mouse sulla directory
src
e seleziona Nuovo > XML > File XML valori. - Inserisci il nome del file XML o mantieni quello predefinito.
- Nel menu accanto a Set di origini target, seleziona debug.
- Fai clic su Fine.
Poiché il tipo di build "debug" è stato specificato come set di origine di destinazione, Android Studio crea automaticamente le directory necessarie quando crea il file XML. La struttura di directory risultante è simile alla figura 1.
Gli insiemi di origini attivi hanno un indicatore verde nell'icona per indicare che sono attivi. Al set di risorse debug
viene aggiunto il suffisso [main]
per indicare che verrà unito al set di risorse main
.
Con la stessa procedura, puoi anche creare directory di set di origine per i gusti dei prodotti, come src/demo/
, e creare varianti, come src/demoDebug/
. Inoltre, puoi creare set di origini di test
che hanno come target varianti di build specifiche, ad esempio
src/androidTestDemoDebug/
. Per saperne di più, consulta la sezione su come testare i set di origine.
Modificare le configurazioni degli insiemi di origini predefinite
Se le origini non sono organizzate nella struttura del file del set di origini predefinito che Gradle si aspetta, come descritto nella sezione precedente sulla creazione di set di origini, puoi utilizzare il blocco
sourceSets
per modificare la posizione in cui Gradle cerca di raccogliere i file per ogni componente di un set di origini.
Il blocco sourceSets
deve essere
nel blocco android
. Non è necessario riposizionare i file di origine. Devi solo fornire a Gradle i percorsi relativi al file build.gradle.kts
a livello di modulo in cui Gradle può trovare i file per ogni componente dell'insieme di origini. Per scoprire quali componenti puoi configurare e se puoi mapparli a più file o directory, consulta la documentazione dell'API del plug-in Gradle per Android.
Il seguente codice di esempio mappa le origini dalla directory app/other/
a determinati componenti dell'insieme di origini main
e modifica la directory
principale dell'insieme di origini androidTest
:
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' ... } } } ...
Tieni presente che una directory di origine può appartenere a un solo set di origini. Ad esempio, non puoi condividere le stesse origini di test con gli insiemi di origini test
e androidTest
. Questo accade perché Android Studio crea moduli IntelliJ separati per ogni set di origine e non può supportare radici dei contenuti duplicate nei set di origine.
Creare con set di origini
Puoi utilizzare le directory dei set di origine per contenere il codice e le risorse che vuoi impacchettare solo con determinate configurazioni. Ad esempio, se stai compilando la variante di compilazione "demoDebug", che è il prodotto incrociato di un flavor del prodotto "demo" e del tipo di compilazione "debug", Gradle esamina queste directory e assegna loro la seguente priorità:
-
src/demoDebug/
(set di origine della variante di compilazione) -
src/debug/
(insieme di origini del tipo di compilazione) -
src/demo/
(set di origini delle versioni prodotto) -
src/main/
(set di origini principali)
I set di origini creati per combinazioni di varianti del prodotto devono includere tutte le dimensioni delle varianti. Ad esempio, l'insieme di origini delle varianti di build deve essere la combinazione del tipo di build e di tutte le dimensioni del gusto. L'unione di codice e risorse che coinvolgono cartelle che coprono più dimensioni del gusto, ma non tutte, non è supportata.
Se combini più sapori di prodotto, la priorità tra i sapori di prodotto è determinata dalla dimensione del sapore a cui appartengono. Quando elenchi le dimensioni del sapore con la proprietà
android.flavorDimensions
, i sapori dei prodotti che appartengono alla prima dimensione del sapore che elenchi hanno una priorità più alta rispetto a quelli appartenenti alla seconda dimensione del sapore e così via. Inoltre,
gli insiemi di origini che crei per combinazioni di varianti di prodotto hanno una priorità superiore rispetto agli insiemi di origini che appartengono a una singola variante di prodotto.
L'ordine di priorità determina quale insieme di origini ha una priorità più elevata quando Gradle combina codice e risorse. Poiché la directory del set di origine demoDebug/
contiene probabilmente file specifici per la variante di compilazione, se demoDebug/
include un file definito anche in
debug/
, Gradle utilizza il file nel set di origine demoDebug/
. Analogamente, Gradle assegna ai file nel tipo di build e ai set di main/
di destinazione del gusto del prodotto una priorità più alta rispetto agli stessi file in main/
.
Gradle prende in considerazione questo ordine di priorità quando applica le seguenti regole di compilazione:
- Tutto il codice sorgente nelle directory
kotlin/
ojava/
viene compilato insieme per generare un unico output.Nota:per una determinata variante di build, Gradle genera un errore di compilazione se rileva due o più directory del set di origine che hanno definito la stessa classe Kotlin o Java. Ad esempio, quando crei un'app di debug, non puoi definire sia
src/debug/Utility.kt
siasrc/main/Utility.kt
, perché Gradle esamina entrambe queste directory durante il processo di compilazione e genera un errore "classe duplicata". Se vuoi versioni diverse diUtility.kt
per tipi di build diversi, ogni tipo di build deve definire la propria versione del file e non includerlo nell'insieme di originimain/
. - I manifest vengono uniti in un unico manifest. La priorità viene assegnata nello stesso ordine dell'elenco nell'esempio precedente. In altre parole, le impostazioni manifest per un tipo di compilazione soppiantano le impostazioni manifest per una versione del prodotto e così via. Per saperne di più, consulta l'articolo sulla unione dei manifest.
- I file nelle directory
values/
vengono uniti. Se due file hanno lo stesso nome, ad esempio due filestrings.xml
, la priorità viene assegnata nello stesso ordine dell'elenco nell'esempio precedente. In altre parole, i valori definiti in un file nell'origine del tipo di build superano i valori definiti nello stesso file in un flavor del prodotto e così via. - Le risorse nelle directory
res/
easset/
vengono pacchettizzate insieme. Se sono presenti risorse con lo stesso nome definite in due o più set di origini, la priorità viene assegnata nello stesso ordine dell'elenco nell'esempio precedente. - Gradle assegna la priorità più bassa alle risorse e ai manifest inclusi con le dipendenze del modulo della libreria durante la compilazione dell'app.
Dichiarare le dipendenze
Per configurare una dipendenza per una variante di build o un
set di origine di test specifico,
prefiggi il nome della variante di build o del set di origine di test prima della
chiave Implementation
, come mostrato nell'esempio seguente:
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' }
Per ulteriori informazioni sulla configurazione delle dipendenze, consulta Aggiungere dipendenze di compilazione.
Utilizza la gestione delle dipendenze basata sulle varianti
Il plug-in Android per Gradle 3.0.0 e versioni successive include un nuovo meccanismo di dipendenza che associa automaticamente le varianti quando utilizzi una libreria. Ciò significa che la variante debug
di un'app utilizza automaticamente la variante debug
di una raccolta e così via. Funziona anche quando si utilizzano i gusti: la variante freeDebug
di un'app consumerà la variante freeDebug
di una libreria.
Affinché il plug-in corrisponda con precisione alle varianti, devi fornire valori di riserva corrispondenti come descritto nella sezione seguente, per i casi in cui non è possibile una corrispondenza diretta.
Ad esempio, supponiamo che la tua app configuri un tipo di build denominato "staging", ma che una delle sue dipendenze della libreria non lo faccia. Quando il plug-in tenta di compilare la versione "di staging" della tua app, non saprà quale versione della libreria utilizzare e visualizzerai un messaggio di errore simile al seguente:
Error:Failed to resolve: Could not resolve project :mylibrary. Required by: project :app
Risolvere gli errori di compilazione relativi alla corrispondenza delle varianti
Il plug-in include elementi DSL per aiutarti a controllare in che modo Gradle risolve le situazioni in cui non è possibile una corrispondenza diretta tra una variante e una dipendenza.
Di seguito è riportato un elenco di problemi relativi alla corrispondenza delle dipendenze in base alle varianti e come risolverli utilizzando le proprietà DSL:La tua app include un tipo di build che una dipendenza di libreria non include.
Ad esempio, la tua app include un tipo di build "staging", ma una dipendenza include solo i tipi di build "debug" e "release".
Tieni presente che non si verificano problemi quando una dipendenza della libreria include un tipo di compilazione diverso da quello della tua app. Questo accade perché il plug-in non richiede mai questo tipo di build dalla dipendenza.
Utilizza
matchingFallbacks
per specificare corrispondenze alternative per un determinato tipo di build, come mostrato di seguito: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'] } } }
Per una determinata dimensione del gusto esistente sia nell'app sia nella sua dipendenza dalla libreria, l'app include i gusti che la libreria non include.
Ad esempio, sia l'app sia le sue dipendenze di libreria includono una dimensione del tipo "livello". Tuttavia, la dimensione "livello" nell'app include le versioni "senza costi" e "a pagamento", ma una dipendenza include solo le versioni "demo" e "a pagamento" per la stessa dimensione.
Tieni presente che per una determinata dimensione del gusto esistente sia nell'app sia nelle sue dipendenze della libreria, non si verificano problemi quando una libreria include un gusto del prodotto che non è presente nell'app. Questo perché il plug-in non richiede mai questa versione dalla dipendenza.
Utilizza
matchingFallbacks
per specificare corrispondenze alternative per la versione del prodotto "senza costi " dell'app, come mostrato di seguito: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'] } } }
Una dipendenza della libreria include una dimensione del gusto che la tua app non ha.
Ad esempio, una dipendenza della libreria include i flavor per una dimensione "minApi", ma la tua app include i flavor solo per la dimensione "livello". Quando vuoi compilare la versione "freeDebug" della tua app, il plug-in non sa se utilizzare la versione "minApi23Debug" o "minApi18Debug" della dipendenza.
Tieni presente che non si verificano problemi se la tua app include una dimensione del gusto non presente in una dipendenza della libreria. Questo accade perché il plug-in abbina i gusti solo delle dimensioni esistenti nella dipendenza. Ad esempio, se una dipendenza non include una dimensione per le ABI, la versione "freeX86Debug" dell'app utilizzerà la versione "freeDebug" della dipendenza.
Utilizza
missingDimensionStrategy
nel bloccodefaultConfig
per specificare il tipo predefinito che il plug-in deve selezionare da ogni dimensione mancante, come mostrato nell'esempio seguente. Puoi anche sostituire le selezioni nel bloccoproductFlavors
, in modo che ogni versione possa specificare una strategia di corrispondenza diversa per una dimensione mancante.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 {} } }
Per ulteriori informazioni, consulta matchingFallbacks
e missingDimensionStrategy
nella documentazione di riferimento DSL del plug-in Android Gradle.
Configura le impostazioni di firma
Gradle non firma l'APK o l'AAB della build di release, a meno che tu non definisca esplicitamente una configurazione di firma per questa build. Se non hai ancora una chiave di firma, genera una chiave di caricamento e un keystore utilizzando Android Studio.
Per configurare manualmente le configurazioni di firma per il tipo di build della release utilizzando le configurazioni di build di Gradle:
- Crea un archivio chiavi. Un archivio chiavi è un file binario contenente un insieme di chiavi private. Devi conservare il tuo keystore in un luogo sicuro.
- Crea una chiave privata. Per firmare l'app per la distribuzione viene utilizzata una chiave privata, che non viene mai inclusa nell'app o comunicata a terze parti non autorizzate.
-
Aggiungi la configurazione della firma al file
build.gradle.kts
a livello di modulo: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 } } }
Nota: non è buona norma di sicurezza includere le password per la chiave di rilascio e il keystore all'interno del file di compilazione. Configura invece il file di compilazione in modo da ottenere queste password dalle variabili di ambiente o chiedi che ti vengano chieste durante il processo di compilazione.
Per ottenere queste password dalle variabili di ambiente:
Kotlin
storePassword = System.getenv("KSTOREPWD") keyPassword = System.getenv("KEYPWD")
Groovy
storePassword System.getenv("KSTOREPWD") keyPassword System.getenv("KEYPWD")
In alternativa, puoi caricare il keystore da un file di proprietà locale. Per motivi di sicurezza, non aggiungere questo file al controllo del codice sorgente. ma configuralo localmente per ogni sviluppatore. Per scoprire di più, leggi Rimuovere le informazioni sulla firma dai file di compilazione.
Dopo aver completato questa procedura, puoi distribuire l'app e pubblicarla su Google Play.
Avviso: conserva l'archivio chiavi e la chiave privata in un luogo sicuro e assicurati di disporre di backup protetti. Se utilizzi la firma dell'app Google Play e perdi la chiave di caricamento, puoi richiedere un ripristino utilizzando Play Console. Se pubblichi un'app senza la firma dell'app di Google Play (per le app create prima di agosto 2021) e perdi la chiave di firma dell'app, non potrai pubblicare aggiornamenti dell'app, poiché devi sempre firmare tutte le versioni dell'app con la stessa chiave.
Firma delle app per Wear OS
Quando pubblichi app per Wear OS, sia l'APK per lo smartwatch sia l'APK facoltativo per lo smartphone devono essere firmati con la stessa chiave. Per ulteriori informazioni sulla creazione del pacchetto e sulla firma delle app per Wear OS, vedi Pacchettizzare e distribuire app Wear.