Configura varianti della build

Questa pagina mostra come configurare le varianti di build per creare versioni diverse della tua app da un singolo progetto e come gestire correttamente le dipendenze e le configurazioni di firma.

Ogni variante build rappresenta una versione diversa dell'app che puoi creare. Ad esempio, potresti voler creare una versione dell'app gratuita con un insieme limitato di contenuti e un'altra versione a pagamento che ne include di più. Puoi anche creare diverse versioni dell'app destinate a dispositivi diversi, in base al livello API o ad altre varianti dei dispositivi.

Le varianti build sono il risultato dell'utilizzo di Gradle tramite un insieme specifico di regole per combinare impostazioni, codice e risorse configurati nei tipi di build e nelle versioni del prodotto. Anche se non configuri direttamente le varianti di build, devi configurare i tipi di build e le versioni di prodotto che le formano.

Ad esempio, una versione di prodotto "demo" potrebbe specificare determinate funzionalità e requisiti del dispositivo, come codice sorgente personalizzato, risorse e livelli minimi di API, mentre il tipo di build "debug" applica impostazioni di build e pacchetti diverse, come le opzioni di debug e le chiavi di firma. La variante di build che combina queste due è la versione "demoDebug" della tua app e include una combinazione delle configurazioni e delle risorse incluse nella versione di prodotto "demo", nel tipo di build "debug" e nel set di origine main/.

Configura 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. Anche se il tipo di build di debug non viene 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 archivio chiavi di debug generico.

Puoi aggiungere il tipo di build di debug alla configurazione se vuoi aggiungere o modificare determinate impostazioni. L'esempio seguente specifica un applicationIdSuffix per il tipo di build di debug e configura un tipo di build "temporaneo" che viene inizializzato utilizzando le impostazioni del tipo di build 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"
        }
    }
}

trendy

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 la sincronizzazione del progetto con la nuova configurazione. Per sincronizzare il progetto, fai clic su Sincronizza ora nella barra di notifica che viene visualizzata quando apporti una modifica o fai clic su Sincronizza progetto dalla barra degli strumenti. Se Android Studio rileva errori di 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 il riferimento BuildType.

Configura le versioni dei prodotti

La creazione di versioni dei prodotti è simile alla creazione dei tipi di build. Aggiungi le versioni di prodotto al blocco productFlavors nella configurazione della build e includi le impostazioni che preferisci. I gusti 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 tutte le versioni nel blocco defaultConfig e ogni versione 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 pacchetto utilizzando l'attributo package nel file manifest di main/. Devi inoltre utilizzare questo nome del pacchetto nel codice sorgente per fare riferimento alla classe R o per risolvere eventuali attività relative o registrazioni di servizi. In questo modo puoi utilizzare applicationId per assegnare a ogni versione di prodotto un ID univoco per la confezione e la distribuzione senza dover modificare il codice sorgente.

Tutti i sapori devono appartenere a una dimensione con nome, ovvero un gruppo di gusti di prodotto. Devi assegnare tutti i gusti a una dimensione versione; in caso contrario, verrà visualizzato 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 flavor, il plug-in Android per Gradle assegna automaticamente tutti i gusti del modulo a quella dimensione.

Il seguente esempio di codice crea una dimensione flavor denominata "version" e aggiunge le versioni "demo" e "full". Questi tipi di versione 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"
        }
    }
}

trendy

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 APK su Google Play, per distribuire la tua app utilizzando il supporto di più APK in Google Play, assegna lo stesso valore applicationId a tutte le varianti e assegna a ogni variante una versionCode diversa. Per distribuire varianti diverse della tua app come app separate in Google Play, devi assegnare un valore applicationId diverso a ogni variante.

Dopo aver creato e configurato i sapori dei prodotti, fai clic su Sincronizza ora nella barra delle notifiche. Al termine della sincronizzazione, Gradle crea automaticamente varianti di build in base ai tuoi tipi di build e ai gusti del prodotto e le assegna un nome in base a <product-flavor><Build-Type>. Ad esempio, se hai creato versioni di prodotto "demo" e "complete" e hai mantenuto i tipi di build "debug" e "release" predefiniti, Gradle crea le seguenti varianti di build:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

Per selezionare la variante di build da creare ed eseguire, vai a Crea > Seleziona variante build e seleziona una variante build dal menu. Per iniziare a personalizzare ogni variante di build con funzionalità e risorse specifiche, devi creare e gestire i set di origini, come descritto in questa pagina.

Modificare l'ID applicazione per le varianti della build

Quando crei un APK o un AAB per la tua app, gli strumenti di creazione 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 in modo che vengano visualizzate come schede separate sul Google Play Store, ad esempio una versione "senza costi" e una "pro", devi creare varianti della build separate, ciascuna con un ID applicazione diverso.

In questo caso, definisci ogni variante di build come un gusto di prodotto distinto. Per ogni versione all'interno del blocco productFlavors, puoi ridefinire la proprietà applicationId oppure aggiungere un segmento all'ID applicazione predefinito utilizzando applicationIdSuffix, come mostrato qui:

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

trendy

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

In questo modo, l'ID applicazione per il sapore di prodotto "gratis" è "com.example.myapp.free".

Puoi anche utilizzare applicationIdSuffix per aggiungere un segmento in base al tuo tipo di build, come mostrato qui:

Kotlin

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

trendy

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

Poiché Gradle applica la configurazione del tipo di build dopo la versione di prodotto, l'ID applicazione per la variante di build "debug gratuito" è "com.example.myapp.free.debug". Questo è utile quando vuoi avere sia il debug sia la build della release 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 APK su Google Play e vuoi utilizzare la stessa scheda dell'app per distribuire più APK che hanno come target una configurazione dispositivo diversa, ad esempio il livello API, devi usare lo stesso ID applicazione per ogni variante della build, ma assegnare a ogni APK un valore versionCode diverso. Per ulteriori informazioni, leggi la sezione Supporto di più APK. La pubblicazione tramite gli AAB non è interessata, poiché utilizza un singolo artefatto che utilizza un singolo codice di 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 ulteriori informazioni, consulta Inserimento di variabili di build nel manifest.

Combinare più gusti di prodotto con le dimensioni dei sapori

In alcuni casi, potresti voler combinare configurazioni di più versioni di prodotto. Ad esempio, potresti voler creare configurazioni diverse per le versioni di prodotto "completo" e "demo" basate sul livello API. A questo scopo, il plug-in Android per Gradle consente di creare più gruppi di gusti di prodotto come dimensioni dei gusti.

Durante la creazione dell'app, Gradle combina una configurazione dei gusti di prodotto di ogni dimensione flavor che definisci, insieme a una configurazione del tipo di build, per creare la variante di build finale. Gradle non combina sapori di prodotti che appartengono alla stessa dimensione gusto.

Il seguente esempio di codice utilizza la proprietà flavorDimensions per creare una dimensione flavor "mode" per raggruppare le versioni "full" e "demo" e una dimensione "api" per raggruppare le configurazioni dei gusti di 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"
      ...
    }
  }
}
...

trendy

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 versioni in ogni dimensione di versione e al numero di tipi di build configurati. Quando Gradle assegna un nome a ogni variante di build o agli artefatti corrispondenti, vengono visualizzate per prime le varianti di prodotto appartenenti alla dimensione flavor con priorità più alta, seguite da quelle delle dimensioni con priorità più bassa e dal tipo di build.

Utilizzando la precedente configurazione di build come esempio, Gradle crea un totale di 12 varianti di build con il seguente schema di denominazione:

  • Variante build: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • APK corrispondente: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • Ad esempio,
    Variante build: minApi24DemoDebug
    APK corrispondente: app-minApi24-demo-debug.apk

Oltre alle directory dei set di origini che puoi creare per ogni singola variante di build e per ogni singola versione di prodotto, puoi anche creare directory del set di origini per ogni combinazione di versioni di prodotto. Ad esempio, puoi creare e aggiungere origini Java alla directory src/demoMinApi24/java/ e Gradle le utilizza solo quando crei una variante che combina queste due versioni di prodotto.

I set di origini che crei per le combinazioni di sapori del prodotto hanno una priorità maggiore rispetto ai set di origini che appartengono a ogni singolo gusto di 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.

Filtra 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 alcune varianti di build non necessarie o che non hanno senso nel contesto del progetto. Per rimuovere determinate configurazioni delle varianti di build, crea un filtro delle varianti nel file build.gradle.kts a livello di modulo.

Ad esempio, utilizzando la configurazione di build della sezione precedente, supponi di voler supportare solo i livelli API 23 e successivi per la versione demo dell'app. Puoi utilizzare il blocco variantFilter per filtrare tutte le configurazioni delle varianti di build che combinano le versioni demo del 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
        }
    }
}
...

trendy

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 della build e aver fatto clic su Sincronizza ora nella barra delle notifiche, Gradle ignora tutte le varianti di build che soddisfano le condizioni da te specificate. Le varianti build non vengono più visualizzate nel menu quando fai clic su Crea > Seleziona variante build dalla barra dei menu o Crea varianti nella barra della finestra degli strumenti.

Crea set di origini

Per impostazione predefinita, Android Studio crea le directory e il set di origine main/ per tutto ciò che vuoi condividere tra tutte le varianti della build. Tuttavia, puoi creare nuovi set di origine per controllare esattamente quali file compila e pacchettizzati da Gradle per tipi di build, versioni di prodotto e combinazioni di versioni di prodotti specifici (quando si utilizzano le dimensioni delle versioni) e creare varianti.

Ad esempio, puoi definire la funzionalità di base nel set di origine main/ e utilizzare i set di origini dei gusti del prodotto per modificare il branding della tua app per clienti diversi oppure includere autorizzazioni speciali e funzionalità di logging 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 certo modo, come il 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'attività Gradle utile che ti mostra come organizzare i file per ciascun tipo di build, versioni di prodotto e varianti di build. Ad esempio, il seguente esempio dell'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, procedi come segue:

  1. Fai clic su Gradle nella barra della finestra degli strumenti.
  2. Vai a MyApplication > Tasks > android e fai doppio clic su sourceSets.

    Per visualizzare la cartella Tasks, devi consentire a Gradle di creare l'elenco delle attività durante la sincronizzazione. A tale scopo, procedi nel seguente modo:

    1. Fai clic su File > Impostazioni > Sperimentale (Android Studio > Impostazioni > Sperimentale su macOS).
    2. Deseleziona Non creare l'elenco di attività Gradle durante la sincronizzazione Gradle.
  3. 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 origini per i file che vuoi utilizzare per eseguire test per la tua app, ad esempio i set di origini di test test/ e androidTest/.

Quando crei una nuova variante di build, Android Studio non crea automaticamente le directory del set di origine, ma offre alcune opzioni per aiutarti. Ad esempio, per creare solo la directory java/ per il tipo di build "debug":

  1. Apri il riquadro Progetto e seleziona la visualizzazione Progetto dal menu nella parte superiore del riquadro.
  2. Vai a MyProject/app/src/.
  3. Fai clic con il pulsante destro del mouse sulla directory src e seleziona Nuovo > Directory.
  4. Dal menu in Set di origini Gradle, seleziona full/java.
  5. Premi Invio.

Android Studio crea una directory del set di origini per il tipo di build di debug, quindi 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 con i valori per il tipo di build "debug":

  1. Nel riquadro Progetto, fai clic con il pulsante destro del mouse sulla directory src e seleziona Nuovo > XML > File XML dei valori.
  2. Inserisci il nome del file XML o mantieni il nome predefinito.
  3. Dal menu accanto a Set di origini di destinazione, seleziona debug.
  4. 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 della directory risultante è simile alla figura 1.

Figura 1. Nuove directory del set di origine per il tipo di build "debug".

I set di origini attive hanno un indicatore verde nell'icona che indica che sono attivi. Il set di origine debug ha il suffisso [main] per indicare che verrà unito al set di origini main.

Utilizzando la stessa procedura, puoi anche creare directory del set di origine per le versioni dei prodotti, come src/demo/, e creare varianti, ad esempio src/demoDebug/. Inoltre, puoi creare set di origini di test che hanno come target varianti di build specifiche, come src/androidTestDemoDebug/. Per saperne di più, consulta la pagina relativa al test dei set di origini.

Modifica le configurazioni dei set di origini predefiniti

Se alcune origini non sono organizzate nella struttura predefinita dei file del set di origine prevista da Gradle, come descritto nella sezione precedente sulla creazione di set di origini, puoi utilizzare il blocco sourceSets per modificare la posizione in cui Gradle cerca i file per ogni componente di un set di origine.

Il blocco sourceSets deve essere nel blocco android. Non è necessario riposizionare i file di origine; devi solo fornire a Gradle i percorsi, in relazione al file build.gradle.kts a livello di modulo, in cui Gradle può trovare i file per ogni componente del set di origine. Per sapere quali componenti puoi configurare e se puoi mapparli su più file o directory, consulta la documentazione relativa all'API per il plug-in Android per Gradle.

Il seguente esempio di codice mappa le origini dalla directory app/other/ a determinati componenti del set di origini main e modifica la directory principale del set 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")
      ...
  }
}
...

trendy

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 origine. Ad esempio, non puoi condividere le stesse origini di test con i set di origini test e androidTest. Questo è dovuto al fatto che Android Studio crea moduli IntelliJ separati per ogni set di origine e non è in grado di supportare le directory principali dei contenuti duplicate nei set di origine.

Crea con set di origine

Puoi utilizzare le directory del set di origine per contenere il codice e le risorse che vuoi pacchettizzare solo con determinate configurazioni. Ad esempio, se stai creando la variante di build "demoDebug", che è il crossproduct di un tipo di build "demo" e "debug", Gradle esamina queste directory e assegna loro la priorità seguente:

  1. src/demoDebug/ (crea set di origini delle varianti)
  2. src/debug/ (set di origine del tipo di build)
  3. src/demo/ (set di origine dei gusti di prodotto)
  4. src/main/ (insieme di sorgenti principale)

I set di origini creati per combinazioni di sapori di prodotti devono includere tutte le dimensioni dei gusti. Ad esempio, il set di origini della variante build deve essere la combinazione del tipo di build e di tutte le dimensioni versione flavor. L'unione di codice e risorse che coinvolgono cartelle che coprono più dimensioni versione, ma non tutte, non è supportata.

Se combini più gusti di prodotto, la priorità tra i gusti dei prodotti è determinata dalla dimensione dei sapori a cui appartengono. Quando elenchi le dimensioni dei gusti con la proprietà android.flavorDimensions, i sapori dei prodotti che appartengono alla prima dimensione elenco hanno una priorità maggiore rispetto a quelli appartenenti alla seconda dimensione dei gusti e così via. Inoltre, i set di origini che crei per le combinazioni di sapori dei prodotti hanno una priorità maggiore rispetto ai set di origini che appartengono a un singolo sapore di prodotto.

L'ordine di priorità determina quale set di origine ha una priorità più elevata quando Gradle combina codice e risorse. Poiché la directory del set di origine demoDebug/ contiene probabilmente file specifici per quella variante di build, se demoDebug/ include un file definito anche in debug/, Gradle utilizza il file nel set di origine demoDebug/. Allo stesso modo, Gradle assegna ai file nel tipo di build e nel codice sorgente della versione di prodotto una priorità maggiore rispetto agli stessi file in main/. Gradle prende in considerazione questo ordine di priorità quando applica le seguenti regole di build:

  • Tutto il codice sorgente nelle directory kotlin/ o java/ viene compilato insieme per generare un singolo output.

    Nota: per una determinata variante di build, Gradle genera un errore di build se incontra due o più directory del set di origini che hanno definito la stessa classe Kotlin o Java. Ad esempio, durante la creazione di un'app di debug, non puoi definire sia src/debug/Utility.kt sia src/main/Utility.kt, perché Gradle esamina entrambe queste directory durante il processo di compilazione e genera un errore di "classe duplicata". Se vuoi versioni diverse di Utility.kt per tipi di build diversi, ogni tipo di build deve definire la propria versione del file e non includerla nel set di origine main/.

  • I manifest vengono uniti in un unico file manifest. La priorità viene assegnata nello stesso ordine dell'elenco nell'esempio precedente. In altre parole, le impostazioni del file manifest per un tipo di build sostituiscono le impostazioni del file manifest per una versione di prodotto e così via. Per ulteriori informazioni, consulta la sezione sull'unione dei file manifest.
  • I file nelle directory values/ vengono uniti. Se due file hanno lo stesso nome, ad esempio due file strings.xml, la priorità viene assegnata nello stesso ordine dell'elenco nell'esempio precedente. In altre parole, i valori definiti in un file nel set di origine del tipo di build sostituiscono i valori definiti nello stesso file in una versione di prodotto e così via.
  • Le risorse nelle directory res/ e asset/ 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 alle risorse e ai manifest inclusi con le dipendenze dei moduli libreria la priorità più bassa durante la creazione dell'app.

Dichiarare le dipendenze

Per configurare una dipendenza per una variante di build o un set di origini di test specifici, anteponi il nome della variante build o del set di origini 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.5.1")
}

trendy

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.5.1'
}

Per ulteriori informazioni sulla configurazione delle dipendenze, consulta Aggiungere dipendenze di build.

Usa la gestione delle dipendenze sensibile 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 consuma automaticamente la variante debug di una libreria e così via. Funziona anche quando si utilizzano le versioni: la variante freeDebug di un'app utilizzerà la variante freeDebug di una libreria.

Affinché il plug-in possa abbinare con precisione le varianti, devi fornire elementi di riserva corrispondenti come descritto nella sezione seguente, nei casi in cui non è possibile una corrispondenza diretta.

Ad esempio, supponi che la tua app configuri un tipo di build denominato "temporaneo" e che una delle sue dipendenze di libreria non lo faccia. Quando il plug-in tenta di creare la versione di "gestione temporanea" della tua app, non saprà quale versione della libreria utilizzare e verrà visualizzato un messaggio di errore simile al seguente:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

Risolvi gli errori di build 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 delle varianti tra un'app e una dipendenza.

Di seguito è riportato un elenco di problemi relativi alla corrispondenza delle dipendenze sensibile alle varianti e di come risolverli utilizzando le proprietà DSL:

  • La tua app include un tipo di build che non è rappresentato da una dipendenza di libreria.

    Ad esempio, la tua app include un tipo di build "temporaneo", ma una dipendenza include solo i tipi di build "debug" e "release".

    Tieni presente che non ci sono problemi quando una dipendenza di libreria include un tipo di build diverso dalla tua app. Questo perché il plug-in non richiede mai quel tipo di build dalla dipendenza.

    Utilizza matchingFallbacks per specificare corrispondenze alternative per un determinato tipo di build, 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")
            }
        }
    }

    trendy

    // 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 flavor che esiste sia nell'app sia nella sua dipendenza dalla libreria, la tua app include versioni non incluse nella libreria.

    Ad esempio, sia la tua app sia le sue dipendenze di libreria includono una dimensione flavor "livello". Tuttavia, la dimensione "livello" nell'app include i gusti "gratis" e "a pagamento", ma una dipendenza include solo i gusti "demo" e "a pagamento" per la stessa dimensione.

    Tieni presente che, per una determinata dimensione flavor che esiste sia nell'app sia nelle sue dipendenze di libreria, non si verifica alcun problema quando una libreria include una versione di prodotto diversa dalla tua app. Questo perché il plug-in non richiede mai questo flavor alla dipendenza.

    Utilizza matchingFallbacks per specificare corrispondenze alternative per il sapore 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")
            }
        }
    }
    

    trendy

    // 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 dalla libreria include una dimensione flavor che la tua app non fa.

    Ad esempio, una dipendenza di libreria include gusti per una dimensione "minApi", ma la tua app include gusti 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 ci sono problemi quando la tua app include una dimensione flavor a differenza di una dipendenza di libreria. Il motivo è che il plug-in abbina le versioni delle sole dimensioni esistenti nella dipendenza. Ad esempio, se una dipendenza non include una dimensione per le ABI, la versione "freeX86Debug" della tua app utilizzerà la versione "freeDebug" della dipendenza.

    Usa missingDimensionStrategy nel blocco defaultConfig per specificare la versione predefinita per il plug-in da selezionare da ogni dimensione mancante, come mostrato nell'esempio che segue. Puoi anche sostituire le selezioni nel blocco productFlavors, in modo che ogni gusto 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") {}
        }
    }
    

    trendy

    // 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 della release a meno che 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 archivio chiavi utilizzando Android Studio.

Per configurare manualmente le configurazioni di firma per il tipo di build di release utilizzando le configurazioni di build Gradle:

  1. Crea un archivio chiavi. Un keystore è un file binario che contiene un insieme di chiavi private. Devi conservare il tuo archivio chiavi in un luogo sicuro.
  2. 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 comunicata a terze parti non autorizzate.
  3. Aggiungi la configurazione di 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")
            }
        }
    }

    trendy

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            release {
                storeFile file("myreleasekey.keystore")
                storePassword "password"
                keyAlias "MyReleaseKey"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }

Nota: l'inclusione delle password per la chiave di rilascio e l'archivio chiavi nel file di build non è una buona prassi di sicurezza. Configura invece il file di build per ottenere queste password dalle variabili di ambiente o per fare in modo che il processo di compilazione ti chieda di inserire queste password.

Per ottenere queste password dalle variabili di ambiente:

Kotlin

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

trendy

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

In alternativa, puoi caricare l'archivio chiavi da un file delle proprietà locali. Per motivi di sicurezza, non aggiungere questo file al controllo del codice sorgente. Configurala invece localmente per ogni sviluppatore. Per scoprire di più, consulta la pagina Rimuovere le informazioni di firma dai file di build.

Dopo aver completato la procedura, puoi distribuire la tua app e pubblicarla su Google Play.

Avviso: conserva l'archivio chiavi e la chiave privata in un luogo sicuro e assicurati di avere backup protetti degli stessi. Se usi 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 alcun aggiornamento 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 dell'orologio che l'APK del telefono facoltativo devono essere firmati con la stessa chiave. Per maggiori informazioni sulla confezione e sulla firma delle app Wear OS, consulta la pagina Impacchettare e distribuire app Wear.