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 compilazione rappresenta una versione diversa della tua app che puoi creare. Ad esempio, potresti creare una versione senza costi della tua app con un insieme limitato di contenuti e un'altra versione a pagamento che ne includa di più. Puoi anche creare versioni diverse della tua app destinate a dispositivi diversi, in base al livello API o ad altre varianti del dispositivo.
Le build variant 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 nelle varianti di prodotto. Anche se non configuri direttamente le varianti di compilazione, configuri i tipi di compilazione e le versioni prodotto che le compongono.
Ad esempio, una versione prodotto "demo" potrebbe specificare determinate funzionalità e requisiti del dispositivo, come codice sorgente, risorse e livelli API minimi personalizzati, mentre il tipo di compilazione "debug" applica impostazioni di build e pacchettizzazione diverse, come opzioni di debug e chiavi di firma. La variante di compilazione che combina questi due elementi è la versione "demoDebug" della tua app e include una combinazione delle configurazioni e delle risorse incluse nella versione prodotto "demo", nel tipo di compilazione "debug" e nel set di risorse 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 compilazione di debug e release. Sebbene il tipo di compilazione di debug non venga visualizzato nel file di configurazione della compilazione, 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 compilazione 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" 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" } } }
Alla moda
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 della 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 visualizzata quando apporti una modifica o fai clic su
Sincronizza progetto
dalla barra degli strumenti. Se Android
Studio rileva errori nella configurazione, viene visualizzata la finestra
Messaggi per descrivere il problema.
Per saperne di più su tutte le proprietà che puoi configurare con i tipi di build,
consulta il riferimento
BuildType.
Configurare le varianti del prodotto
La creazione di varianti di prodotto è simile alla creazione di tipi di build. Aggiungi varianti del prodotto al blocco
productFlavors nella configurazione di compilazione e includi le impostazioni che preferisci.
Le varianti del prodotto supportano le stesse proprietà di
defaultConfig, perché defaultConfig
appartiene effettivamente alla classe
ProductFlavor. Ciò significa che puoi fornire la configurazione di base per tutte le varianti nel blocco defaultConfig e ogni variante può modificare uno qualsiasi di questi valori predefiniti, ad esempio applicationId. Per
scoprire di più sull'ID applicazione, leggi
Impostare l'ID applicazione.
Nota:devi comunque specificare un nome di pacchetto utilizzando l'attributo
package
nel file manifest main/. Devi anche utilizzare questo nome di pacchetto nel codice sorgente per fare riferimento alla classe R o per risolvere qualsiasi registrazione relativa di attività o servizi. In questo modo puoi utilizzare
applicationId per assegnare a ogni versione prodotto un ID univoco per
la pacchettizzazione e la distribuzione senza dover modificare il codice sorgente.
Tutte le versioni devono appartenere a una dimensione versioni denominata, ovvero un gruppo di versioni prodotto. Devi assegnare tutte le versioni a una dimensione versioni, altrimenti riceverai il seguente errore di build.
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 una sola dimensione versioni, il plug-in Android per Gradle assegna automaticamente tutte le versioni del modulo a quella dimensione.
Il seguente esempio di codice crea una dimensione versioni denominata "version" e aggiunge le versioni prodotto "demo" e "full". Questi sapori 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" } } }
Alla moda
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 legacy (creata prima di agosto 2021) che distribuisci utilizzando gli APK su Google Play, per distribuire l'app utilizzando il supporto di più APK in 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 varianti di prodotto, fai clic su Sincronizza
ora nella barra delle notifiche. Una volta completata la sincronizzazione, Gradle
crea automaticamente le varianti di build in base ai tipi di build e alle varianti
di prodotto e le denomina in base a
<product-flavor><Build-Type>. Ad esempio, se hai
creato le varianti di prodotto "demo" e "full" e hai mantenuto i tipi di build
"debug" e
"release" predefiniti, Gradle crea le seguenti varianti di build:
-
demoDebug -
demoRelease -
fullDebug -
fullRelease
Per selezionare quale variante di compilazione creare ed eseguire, vai a Build > Select Build Variant e seleziona una variante di compilazione dal menu. Per iniziare a personalizzare ogni variante di build con le proprie funzionalità e risorse, devi creare e gestire i 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 taggano 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 visualizzare come schede separate nel Google Play Store, ad esempio una versione "senza costi" e una "pro",
devi creare varianti di build separate, ognuna con un ID applicazione diverso.
In questo caso, definisci ogni variante di compilazione come una
versione prodotto separata. Per ogni variante
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" } } }
Alla moda
android { defaultConfig { applicationId "com.example.myapp" } productFlavors { free { applicationIdSuffix ".free" } pro { applicationIdSuffix ".pro" } } }
In questo modo, l'ID applicazione per la versione prodotto "free" è "com.example.myapp.free".
Puoi anche utilizzare applicationIdSuffix per aggiungere un segmento in base al tuo tipo di compilazione, come mostrato qui:
Kotlin
android { ... buildTypes { getByName("debug") { applicationIdSuffix = ".debug" } } }
Alla moda
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
Poiché Gradle applica la configurazione del tipo di compilazione dopo la versione prodotto, l'ID applicazione per la variante di compilazione "debug senza costi" è "com.example.myapp.free.debug". Ciò è utile quando vuoi avere sia la build di debug sia quella di rilascio sullo stesso dispositivo, perché due app non possono avere lo stesso ID applicazione.
Se hai un'app legacy (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 che hanno come target una configurazione del dispositivo diversa, ad esempio il livello API, devi utilizzare lo stesso ID applicazione per ogni variante di compilazione, ma assegnare a ogni APK unversionCode diverso. Per maggiori informazioni, leggi l'articolo
Supporto di più APK. La pubblicazione
utilizzando 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 build, Gradle sostituisce questo tag con l'ID applicazione effettivo. Per saperne di più, consulta Inserire variabili di build nel manifest.
Combina più gusti di prodotti con le dimensioni del gusto
In alcuni casi, potresti voler combinare le configurazioni di più varianti di prodotto. Ad esempio, potresti voler creare configurazioni diverse per le varianti di prodotto "completa" e "demo" in base al livello API. A questo scopo, il plug-in Android per Gradle ti consente di creare più gruppi di versioni prodotto come dimensioni versioni.
Quando crei l'app, Gradle combina una configurazione di versione prodotto di ogni dimensione versioni che definisci, insieme a una configurazione del tipo di compilazione, per creare la variante di compilazione finale. Gradle non combina le varianti di prodotto che appartengono alla stessa dimensione della variante.
Il seguente esempio di codice utilizza la proprietà
flavorDimensions per creare una dimensione versioni "mode" per raggruppare le versioni prodotto "full" e "demo" e una dimensione versioni "api" per raggruppare le configurazioni delle versioni prodotto in base al livello 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" ... } } } ...
Alla moda
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 compilazione create da Gradle è uguale al prodotto del numero di versioni in ogni dimensione versioni e del numero di tipi di compilazione che configuri. Quando Gradle assegna un nome a ogni variante di compilazione o agli artefatti corrispondenti, le versioni prodotto appartenenti alla dimensione versioni con priorità più alta vengono visualizzate per prime, seguite da quelle delle dimensioni versioni con priorità più bassa, seguite dal tipo di compilazione.
Utilizzando la configurazione di compilazione precedente come esempio, Gradle crea un totale di 12 varianti di compilazione 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 compilazione:
minApi24DemoDebug - APK corrispondente:
app-minApi24-demo-debug.apk
Oltre alle directory dei set di risorse che puoi creare per ogni variante di compilazione e ogni versione prodotto, puoi anche creare directory dei set di risorse per ogni combinazione di versioni prodotto. Ad esempio, puoi creare
e aggiungere origini Java alla directory src/demoMinApi24/java/,
e Gradle utilizza queste origini solo quando crea una variante che combina
queste due varianti del prodotto.
I set di risorse che crei per le combinazioni di versioni prodotto hanno una priorità più alta rispetto ai set di risorse che appartengono a ogni singola versione prodotto. Per scoprire di più sui set di origini e su come Gradle unisce le risorse, leggi la sezione su come creare set di origini.
Filtrare le varianti
Gradle crea una variante di compilazione per ogni combinazione possibile di versioni prodotto e tipi di compilazione che configuri. Tuttavia, potrebbero esserci alcune
varianti di build che non ti servono 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 come esempio la configurazione di compilazione della sezione precedente, supponiamo che tu preveda di supportare solo i livelli API 23 e superiori per la versione demo dell'app. Puoi utilizzare il blocco
variantFilter per filtrare tutte le configurazioni delle varianti di compilazione che combinano le versioni 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 } } } ...
Alla moda
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
ora nella barra delle notifiche, Gradle ignora tutte le varianti di compilazione che soddisfano
le condizioni specificate. Le varianti di build non vengono più visualizzate nel menu
quando fai clic su Build > Select Build Variant (Build > Seleziona variante di build) dalla barra dei menu
o su Build Variants (Varianti di build)
nella
barra della finestra degli strumenti.
Creare set di fonti
Per impostazione predefinita, Android Studio crea il main/
set di risorse e le directory per
tutto ciò che vuoi condividere tra tutte le varianti di compilazione. Tuttavia, puoi
creare nuovi set di origini per controllare esattamente quali file vengono compilati e
pacchettizzati da Gradle per tipi di build, varianti di prodotto, combinazioni di
varianti di prodotto (quando utilizzi le dimensioni
delle varianti) e varianti di build specifici.
Ad esempio, puoi definire la funzionalità di base nel set di risorse main/ e utilizzare i set di risorse delle versioni prodotto per modificare il branding della tua app per diversi client oppure includere autorizzazioni speciali e funzionalità di logging solo per le varianti di compilazione che utilizzano il tipo di compilazione di debug.
Gradle prevede che i file e le directory del set di risorse siano organizzati in un determinato
modo, simile al set di risorse main/. Ad esempio, Gradle
si aspetta che i file di classe Kotlin o Java specifici per il tipo di compilazione "debug" si trovino
nelle directory src/debug/kotlin/ o src/debug/java/.
Il plug-in Android per Gradle fornisce un'attività Gradle utile che mostra come organizzare i file per ciascun tipo di build, variante e versione del prodotto. Ad esempio, il seguente esempio dall'output dell'attività descrive dove Gradle prevede di trovare determinati file per il tipo di build "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 MyApplication > Tasks > android e fai doppio clic su sourceSets.
Per visualizzare la cartella Tasks, devi consentire a Gradle di creare l'elenco di attività durante la sincronizzazione. Per farlo, segui questi passaggi:
- Fai clic su File > Impostazioni > Sperimentale (Android Studio > Impostazioni > Sperimentale su macOS).
- Deseleziona Non creare l'elenco di attività Gradle durante la sincronizzazione di Gradle.
- Dopo che Gradle esegue l'attività, si apre la finestra Esegui per visualizzare l'output.
Nota:l'output dell'attività mostra anche come organizzare i set di origini
per i file che vuoi utilizzare per eseguire i test per la tua app, ad esempio i
test/ e androidTest/
set di origini di test.
Quando crei una nuova variante di compilazione, Android Studio non crea le directory del set di risorse per te, ma ti offre alcune opzioni per aiutarti. 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 all'app
MyProject/app/src/. - Fai clic con il tasto destro del mouse sulla directory
srce seleziona Nuovo > Directory. - Dal menu in Gradle Source Sets, seleziona full/java.
- Premi Invio.
Android Studio crea una directory del set di risorse per il tipo di compilazione 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 compilazione specifica.
Ad esempio, per creare un file XML dei valori per il tipo di compilazione "debug":
- Nel riquadro Progetto, fai clic con il tasto destro del mouse sulla directory
srce seleziona Nuovo > XML > File XML valori. - Inserisci il nome del file XML o mantieni il nome predefinito.
- Dal menu accanto a Target Source Set, seleziona debug.
- Fai clic su Fine.
Poiché il tipo di compilazione "debug" è stato specificato come set di risorse di destinazione, Android Studio crea automaticamente le directory necessarie quando crea il file XML. La struttura di directory risultante è simile a quella della figura 1.
Figura 1. Nuove directory del set di risorse per il tipo di compilazione "debug".
I set di fonti attivi hanno un indicatore verde nell'icona per mostrare che sono attivi. Il set di risorse
debug ha il suffisso [main] per indicare che verrà unito
al set di risorse main.
Utilizzando la stessa procedura, puoi anche creare directory di set di risorse per
versioni prodotto, ad esempio src/demo/, e varianti di compilazione, ad esempio
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ù, leggi l'articolo
Testare i set di origini.
Modificare le configurazioni predefinite dei set di risorse
Se hai origini non organizzate nella struttura del file del set di risorse predefinito
prevista da Gradle, come descritto nella sezione precedente sulla
creazione di set di risorse, puoi utilizzare il blocco
sourceSets per modificare la posizione in cui Gradle cerca i file per ogni componente di un set di risorse.
Il blocco sourceSets deve trovarsi
nel blocco android. Non è necessario spostare i file sorgente; 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 del set di risorse. Per scoprire quali componenti puoi
configurare e se puoi mapparli a più file o directory,
consulta la documentazione di riferimento dell'API del plug-in Android per Gradle.
Il seguente esempio di codice mappa le origini dalla directory app/other/
a determinati componenti del set di risorse main e modifica la
directory root del set di risorse 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") ... } } ...
Alla moda
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 risorse. Ad esempio, non puoi condividere le stesse origini dei test con i set di origini test e androidTest. Questo
perché Android Studio crea moduli IntelliJ separati per ogni set di risorse e non può supportare
radici dei contenuti duplicati nei set di risorse.
Creare con i set di origini
Puoi utilizzare le directory dei set di risorse per contenere il codice e le risorse che vuoi includere nel pacchetto solo con determinate configurazioni. Ad esempio, se stai creando la variante di compilazione "demoDebug", che è il prodotto incrociato di una versione prodotto "demo" e di un tipo di compilazione "debug", Gradle esamina queste directory e assegna loro la seguente priorità:
-
src/demoDebug/(set di risorse della variante di compilazione) -
src/debug/(set di risorse del tipo di compilazione) -
src/demo/(set di risorse delle versioni prodotto) -
src/main/(set di risorse principale)
I set di origini creati per le combinazioni di gusti dei prodotti devono includere tutte le dimensioni del gusto. Ad esempio, il set di risorse della variante di compilazione deve essere la combinazione del tipo di compilazione e di tutte le dimensioni delle versioni. L'unione di codice e risorse che coinvolgono cartelle che coprono più dimensioni di variante, ma non tutte, non è supportata.
Se combini più gusti
di prodotto, la priorità tra i gusti del prodotto è determinata dalla dimensione
a cui appartengono. Quando elenchi le dimensioni versioni con la proprietà
android.flavorDimensions, le versioni prodotto che
appartengono alla prima dimensione versioni che elenchi hanno una priorità maggiore rispetto
a quelle che appartengono alla seconda dimensione versioni e così via. Inoltre,
i set di risorse che crei per le combinazioni di versioni prodotto hanno una priorità
maggiore rispetto ai set di risorse che appartengono a una singola versione prodotto.
L'ordine di priorità determina quale insieme di sorgenti ha una priorità maggiore quando Gradle combina codice e risorse. Poiché la directory del set di risorse demoDebug/
contiene probabilmente file specifici per quella variante di compilazione, se demoDebug/ include un file definito anche in
debug/, Gradle utilizza il file nel set di risorse demoDebug/. Allo stesso modo, Gradle assegna una priorità più alta ai file nei set di risorse del tipo di compilazione e della versione prodotto rispetto agli stessi file in main/.
Gradle considera questo ordine di priorità quando applica le seguenti regole di build:
- Tutto il codice sorgente nelle directory
kotlin/ojava/viene compilato insieme per generare un unico output.Nota:per una determinata variante di compilazione, Gradle genera un errore di build se rileva due o più directory di set di risorse che hanno definito la stessa classe Kotlin o Java. Ad esempio, quando crei un'app di debug, non puoi definire sia
src/debug/Utility.ktsiasrc/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.ktper diversi tipi di compilazione, ogni tipo di compilazione deve definire la propria versione del file e non includerlo nel set di risorsemain/. - I manifest vengono uniti in un unico manifest. La priorità viene assegnata nello stesso ordine dell'elenco nell'esempio precedente. ovvero le impostazioni del manifest per un tipo di compilazione sostituiscono le impostazioni del manifest per una versione prodotto e così via. Per saperne di più, leggi l'articolo sull'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 dell'esempio precedente. ovvero i valori definiti in un file nel set di risorse del tipo di compilazione ignorano i valori definiti nello stesso file in una versione prodotto e così via. - Le risorse nelle directory
res/easset/vengono pacchettizzate insieme. Se sono definite risorse con lo stesso nome 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 nelle dipendenze dei moduli della libreria durante la creazione dell'app.
Dichiarazione di dipendenze
Per configurare una dipendenza per una variante di compilazione specifica o un set di risorse di test, anteponi il nome della variante di compilazione o del set di risorse di test alla parola 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") }
Alla moda
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 saperne di più sulla configurazione delle dipendenze, consulta Aggiungere dipendenze di build.
Utilizzare la gestione delle dipendenze in base alle varianti
Il plug-in Android per Gradle 3.0.0 e versioni successive include un nuovo meccanismo di dipendenza che abbina automaticamente
le varianti quando viene utilizzata una libreria. Ciò significa che la variante debug di un'app
utilizza automaticamente la variante debug di una libreria e così via. Funziona anche quando si utilizzano
varianti: la variante freeDebug di un'app utilizzerà la variante freeDebug di una libreria.
Affinché il plug-in possa trovare le varianti con precisione, devi fornire i fallback di corrispondenza 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 compilazione chiamato "staging", ma una delle sue dipendenze della libreria non lo faccia. Quando il plug-in tenta di creare la versione "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 build relativi alla corrispondenza delle varianti
Il plug-in include elementi DSL per aiutarti a controllare il modo in cui Gradle risolve le situazioni in cui non è possibile una corrispondenza diretta tra una variante di un'app e una dipendenza.
Di seguito è riportato un elenco di problemi relativi alla corrispondenza delle dipendenze sensibili alle varianti e come risolverli utilizzando le proprietà DSL:La tua app include un tipo di compilazione che una dipendenza di libreria non include.
Ad esempio, la tua app include un tipo di compilazione "staging", ma una dipendenza include solo i tipi di compilazione "debug" e "release".
Tieni presente che non si verifica alcun problema quando una dipendenza della libreria include un tipo di build che la tua app non include. Questo perché il plug-in non richiede mai questo tipo di compilazione dalla dipendenza.
Utilizza
matchingFallbacksper specificare corrispondenze alternative per un determinato tipo di compilazione, come mostrato qui: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") } } }
Alla moda
// 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 della variante presente sia nell'app sia nella relativa dipendenza di libreria, l'app include varianti non presenti nella libreria.
Ad esempio, sia la tua app sia le sue dipendenze di libreria includono una dimensione versioni "livello". Tuttavia, la dimensione "livello" nell'app include le varianti "senza costi" e "a pagamento", mentre una dipendenza include solo le varianti "demo" e "a pagamento" per la stessa dimensione.
Tieni presente che per una determinata dimensione di variante presente sia nell'app sia nelle relative dipendenze di libreria, non si verifica alcun problema quando una libreria include una variante di prodotto che la tua app non include. Questo perché il plug-in non richiede mai questa variante dalla dipendenza.
Utilizza
matchingFallbacksper specificare corrispondenze alternative per la variante di prodotto "senza costi " dell'app, come mostrato qui: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") } } }
Alla moda
// 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 di libreria include una dimensione della variante che la tua app non include.
Ad esempio, una dipendenza di libreria include varianti per una dimensione "minApi", ma la tua app include varianti solo per la dimensione "livello". Quando vuoi creare 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 verifica alcun problema quando la tua app include una dimensione versioni che una dipendenza della libreria non include. Questo perché il plug-in corrisponde alle varianti solo delle dimensioni che esistono nella dipendenza. Ad esempio, se una dipendenza non include una dimensione per le ABI, la versione "freeX86Debug" della tua app utilizzerebbe la versione "freeDebug" della dipendenza.
Utilizza
missingDimensionStrategynel bloccodefaultConfigper specificare il flavor predefinito da cui il plug-in deve scegliere per ogni dimensione mancante, come mostrato nell'esempio seguente. Puoi anche ignorare le selezioni nel bloccoproductFlavors, in modo che ogni variante 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") {} } }
Alla moda
// 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 saperne di più, consulta matchingFallbacks
e missingDimensionStrategy
nel riferimento DSL del plug-in Android per 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 compilazione della release utilizzando le configurazioni di compilazione Gradle:
- Crea un archivio chiavi. Un archivio chiavi è un file binario che contiene un insieme di chiavi private. Devi conservare il keystore in un luogo sicuro.
- Crea una chiave privata. Una chiave privata viene utilizzata per firmare la tua app per la distribuzione e non viene mai inclusa nell'app o divulgata a terze parti non autorizzate.
-
Aggiungi la configurazione di firma al file
build.gradle.ktsa 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") } } }
Alla moda
... android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } } }
Nota:includere le password per la chiave di rilascio e il keystore all'interno del file di build non è una buona pratica di sicurezza. Configura invece il file di build per ottenere queste password dalle variabili di ambiente o fai in modo che il processo di compilazione ti chieda queste password.
Per ottenere queste password dalle variabili di ambiente:
Kotlin
storePassword = System.getenv("KSTOREPWD") keyPassword = System.getenv("KEYPWD")
Alla moda
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. Configuralo invece localmente per ogni sviluppatore. Per saperne di più, leggi Rimuovere le informazioni di firma dai file di build.
Dopo aver completato questa procedura, puoi distribuire la tua app e pubblicarla su Google Play.
Avviso:conserva il keystore e la chiave privata in un luogo sicuro e assicurati di averne eseguito backup sicuri. Se utilizzi la firma dell'app di Google Play e perdi la chiave di caricamento, puoi richiedere una reimpostazione 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 Wear OS
Quando pubblichi app per Wear OS, sia l'APK per lo smartwatch sia l'APK per smartphone facoltativo devono essere firmati con la stessa chiave. Per maggiori informazioni sulla pacchettizzazione e sulla firma delle app Wear OS, vedi Pacchettizzare e distribuire app Wear.