Creare più APK

Attenzione: da agosto 2021, tutte le nuove app devono essere pubblicate come App Bundle. Se pubblichi la tua app su Google Play, crea e carica un Android App Bundle. Quando lo fai, Google Play genera e pubblica automaticamente APK ottimizzati per la configurazione del dispositivo di ogni utente, in modo che scarichi solo il codice e le risorse di cui ha bisogno per eseguire la tua app. La pubblicazione di più APK è utile se la stai pubblicando in uno store che non supporta il formato AAB. In questo caso, devi compilare, firmare e gestire ogni APK autonomamente.

Sebbene sia meglio creare un singolo APK per supportare tutti i dispositivi di destinazione , se possibile, questo potrebbe comportare un APK molto grande a causa dei file che supportano più densità di schermo o interfacce di codice macchina (ABI) per le app. Un modo per ridurre le dimensioni dell'APK è creare più APK contenenti file per ABI o densità dello schermo specifiche.

Gradle può creare APK separati che contengono solo codice e risorse specifiche per ogni densità o ABI. Questa pagina descrive come configurare la compilazione per generare più APK. Se devi creare versioni diverse della tua app che non si basano sulla densità dello schermo o sull'ABI, utilizza le varianti di build.

Configurare la build per più APK

Per configurare la compilazione per più APK, aggiungi un blocco splits al file build.gradle a livello di modulo. All'interno del blocco splits, fornisci un blocco density che specifichi come vuoi che Gradle generi APK per densità o un blocco abi che specifichi come vuoi che Gradle generi APK per ABI. Puoi fornire sia blocchi di densità che di ABI e il sistema di compilazione crea un APK per ogni combinazione di densità e ABI.

Configurare più APK per le densità dello schermo

Per creare APK separati per densità di schermo diverse, aggiungi un blocco density all'interno del blocco splits. Nel blocco density, fornisci un elenco delle densità dello schermo e delle dimensioni dello schermo compatibili che preferisci. Utilizza l'elenco delle dimensioni dello schermo compatibili solo se hai bisogno di elementi <compatible-screens> specifici nel manifest di ogni APK.

Le seguenti opzioni DSL di Gradle vengono utilizzate per configurare più APK per le densità dello schermo:

enable per Groovy, isEnable per lo script Kotlin
Se imposti questo elemento su true, Gradle genera più APK in base alle densità dello schermo che definisci. Il valore predefinito è false.
exclude
Specifica un elenco separato da virgole di densità per le quali non vuoi che Gradle genere APK separati. Utilizza exclude se vuoi generare APK per la maggior parte delle densità, ma devi escluderne alcune che la tua app non supporta.
reset()

Cancella l'elenco predefinito delle densità dello schermo. Da utilizzare solo se combinato con l'elemento include per specificare le densità da aggiungere.

Il seguente snippet imposta l'elenco delle densità su solo ldpi e xxhdpi chiamando reset() per svuotare l'elenco e poi utilizzando include:

reset()                  // Clears the default list from all densities
                         // to no densities.
include "ldpi", "xxhdpi" // Specifies the two densities to generate APKs
                         // for.
include
Specifica un elenco separato da virgole di densità per le quali vuoi che Gradle generi APK. Da utilizzare solo in combinazione con reset() per specificare un elenco esatto di densità.
compatibleScreens

Specifica un elenco separato da virgole delle dimensioni dello schermo compatibili. In questo modo viene inserito un nodo <compatible-screens> corrispondente nel file manifest per ogni APK.

Questa impostazione offre un modo pratico per gestire sia le densità sia le dimensioni dello schermo nella stessa sezione build.gradle. Tuttavia, l'utilizzo di <compatible-screens> può limitare i tipi di dispositivi con cui la tua app è compatibile. Per metodi alternativi per supportare schermi di dimensioni diverse, consulta la panoramica della compatibilità con lo schermo.

Poiché ogni APK basato sulla densità dello schermo include un tag <compatible-screens> con limitazioni specifiche sui tipi di schermo supportati dall'APK, anche se pubblichi diversi APK, alcuni nuovi dispositivi non corrispondono ai tuoi filtri APK. Di conseguenza, Gradle genera sempre un APK universale aggiuntivo che contiene asset per tutte le densità dello schermo e non include un tag <compatible-screens>. Pubblica questo APK universale insieme agli APK per densità per fornire un'opzione di riserva per i dispositivi che non corrispondono agli APK con un tag <compatible-screens>.

L'esempio seguente genera un APK separato per ogni densità dello schermo, ad eccezione di ldpi, xxhdpi e xxxhdpi. Per farlo, utilizza exclude per rimuovere queste tre densità dall'elenco predefinito di tutte le densità.

Groovy

android {
  ...
  splits {

    // Configures multiple APKs based on screen density.
    density {

      // Configures multiple APKs based on screen density.
      enable true

      // Specifies a list of screen densities you don't want Gradle to create multiple APKs for.
      exclude "ldpi", "xxhdpi", "xxxhdpi"

      // Specifies a list of compatible screen size settings for the manifest.
      compatibleScreens 'small', 'normal', 'large', 'xlarge'
    }
  }
}

Kotlin

android {
    ...
    splits {

        // Configures multiple APKs based on screen density.
        density {

            // Configures multiple APKs based on screen density.
            isEnable = true

            // Specifies a list of screen densities you don't want Gradle to create multiple APKs for.
            exclude("ldpi", "xxhdpi", "xxxhdpi")

            // Specifies a list of compatible screen size settings for the manifest.
            compatibleScreens("small", "normal", "large", "xlarge")
        }
    }
}

Per ulteriori dettagli sulla personalizzazione di diverse varianti di build della tua app per dispositivi e tipi di schermo specifici, consulta Dichiarare il supporto di schermi con limitazioni.

Configurare più APK per le ABI

Per creare APK separati per ABI diversi, aggiungi un blocco abi all'interno del blocco splits. Nel blocco abi, fornisci un elenco di ABI desiderati.

Le seguenti opzioni DSL di Gradle vengono utilizzate per configurare più APK per ABI:

enable per Groovy o isEnable per lo script Kotlin
Se imposti questo elemento su true, Gradle genera più APK in base alle ABI che definisci. Il valore predefinito è false.
exclude
Specifica un elenco separato da virgole di ABI per i quali non vuoi che Gradle generi APK separati. Utilizza exclude se vuoi generare APK per la maggior parte degli ABI, ma devi escludere alcuni ABI non supportati dalla tua app.
reset()

Cancella l'elenco predefinito di ABI. Da utilizzare solo se combinato con l'elemento include per specificare gli ABI da aggiungere.

Il seguente snippet imposta l'elenco di ABI solo su x86 e x86_64 chiamando reset() per svuotare l'elenco e poi utilizzando include:

reset()                 // Clears the default list from all ABIs to no ABIs.
include "x86", "x86_64" // Specifies the two ABIs we want to generate APKs for.
include
Specifica un elenco separato da virgole di ABI per i quali vuoi che Gradle generi APK. Da utilizzare solo in combinazione con reset() per specificare un elenco esatto di ABI.
universalApk per Groovy o isUniversalApk per script Kotlin

Se true, Gradle genera un APK universale oltre agli APK per ABI. Un APK universale contiene codice e risorse per tutte le ABI in un unico APK. Il valore predefinito è false.

Tieni presente che questa opzione è disponibile solo nel blocco splits.abi. Quando crei più APK in base alla densità dello schermo, Gradle genera sempre un APK universale che contiene codice e risorse per tutte le densità dello schermo.

L'esempio seguente genera un APK separato per ogni ABI: x86 e x86_64. Per farlo, utilizza reset() per iniziare con un elenco vuoto di ABI, seguito da include con un elenco di ABI a cui viene assegnato un APK.

Groovy

android {
  ...
  splits {

    // Configures multiple APKs based on ABI.
    abi {

      // Enables building multiple APKs per ABI.
      enable true

      // By default all ABIs are included, so use reset() and include to specify that you only
      // want APKs for x86 and x86_64.

      // Resets the list of ABIs for Gradle to create APKs for to none.
      reset()

      // Specifies a list of ABIs for Gradle to create APKs for.
      include "x86", "x86_64"

      // Specifies that you don't want to also generate a universal APK that includes all ABIs.
      universalApk false
    }
  }
}

Kotlin

android {
  ...
  splits {

    // Configures multiple APKs based on ABI.
    abi {

      // Enables building multiple APKs per ABI.
      isEnable = true

      // By default all ABIs are included, so use reset() and include to specify that you only
      // want APKs for x86 and x86_64.

      // Resets the list of ABIs for Gradle to create APKs for to none.
      reset()

      // Specifies a list of ABIs for Gradle to create APKs for.
      include("x86", "x86_64")

      // Specifies that you don't want to also generate a universal APK that includes all ABIs.
      isUniversalApk = false
    }
  }
}

Per un elenco degli ABI supportati, consulta ABI supportati.

Progetti senza codice nativo/C++

Per i progetti senza codice nativo/C++, il riquadro Varianti di build contiene due colonne: Modulo e Variante di build attiva, come mostrato nella figura 1.

Riquadro Crea varianti
Figura 1. Il riquadro Varianti di compilazione contiene due colonne per i progetti senza codice nativo/C++.

Il valore Active Build Variant (Variante di build attiva) per il modulo determina la variante di build di cui è stato eseguito il deployment e che è visibile nell'editor. Per passare da una variante all'altra, fai clic sulla cella Variante di compilazione attiva per un modulo e scegli la variante che ti interessa dal campo dell'elenco.

Progetti con codice nativo/C++

Per i progetti con codice nativo/C++, il riquadro Varianti di build contiene tre colonne: Modulo, Variante di build attiva e ABI attivo, come mostrato nella figura 2.

Figura 2. Il riquadro Varianti di build aggiunge la colonna ABI attivo per i progetti con codice nativo/C++.

Il valore Active Build Variant (Variante di build attiva) per il modulo determina la variante di build di cui viene eseguito il deployment ed è visibile nell'editor. Per i moduli nativi, il valore ABI attivo determina l'ABI utilizzato dall'editor, ma non influisce su ciò che viene disegnato.

Per modificare il tipo di build o l'ABI:

  1. Fai clic sulla cella della colonna Variante di build attiva o ABI attivo.
  2. Scegli la variante o l'ABI che ti interessa dal campo dell'elenco. Viene eseguita automaticamente una nuova sincronizzazione.

La modifica di una delle colonne di un modulo di app o libreria applica la modifica a tutte le righe dipendenti.

Configurare il controllo delle versioni

Per impostazione predefinita, quando Gradle genera più APK, ogni APK ha le stesse informazioni sulla versione, come specificato nel file build.gradle o build.gradle.kts a livello di modulo. Poiché il Google Play Store non consente più APK per la stessa app con tutte le stesse informazioni sulla versione, devi assicurarti che ogni APK abbia un valore versionCode univoco prima di caricarlo sul Play Store.

Puoi configurare il file build.gradle a livello di modulo in modo da eseguire l'override del file versionCode per ogni APK. Creando una mappatura che assegna un valore numerico univoco per ogni ABI e densità per cui configuri più APK, puoi sostituire il codice di versione in uscita con un valore che combina il codice di versione definito all'interno del blocco defaultConfig o productFlavors con il valore numerico assegnato alla densità o all'ABI.

Nell'esempio seguente, l'APK per l'ABI x86 viene assegnato un versionCode pari a 2004 e l'ABI x86_64 viene assegnato un versionCode pari a 3004.

L'assegnazione di codici di versione con incrementi elevati, ad esempio 1000, consente di assegnare in un secondo momento codici di versione univoci se devi aggiornare l'app. Ad esempio, se defaultConfig.versionCode esegue l'iterazione fino a 5 in un aggiornamento successivo, Gradle assegna un versionCode di 2005 all'APK x86 e 3005 all'APK x86_64.

Suggerimento:se la build include un APK universale, assegnagli un valore versionCode inferiore a quello di qualsiasi altro APK. Poiché Google Play Store installa la versione dell'app compatibile con il dispositivo di destinazione e con il valore versionCode più elevato, l'assegnazione di un valore versionCode inferiore all'APK universale garantisce che Google Play Store provi a installare uno dei tuoi APK prima di passare all'APK universale. Il seguente codice di esempio gestisce questo problema non sostituendo il valore predefinito versionCode di un APK universale.

Groovy

android {
  ...
  defaultConfig {
    ...
    versionCode 4
  }
  splits {
    ...
  }
}

// Map for the version code that gives each ABI a value.
ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3]

// For per-density APKs, create a similar map:
// ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3]

import com.android.build.OutputFile

// For each APK output variant, override versionCode with a combination of
// ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode
// is equal to defaultConfig.versionCode. If you configure product flavors that
// define their own versionCode, variant.versionCode uses that value instead.
android.applicationVariants.all { variant ->

  // Assigns a different version code for each output APK
  // other than the universal APK.
  variant.outputs.each { output ->

    // Stores the value of ext.abiCodes that is associated with the ABI for this variant.
    def baseAbiVersionCode =
            // Determines the ABI for this variant and returns the mapped value.
            project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))

    // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes,
    // the following code doesn't override the version code for universal APKs.
    // However, because you want universal APKs to have the lowest version code,
    // this outcome is desirable.
    if (baseAbiVersionCode != null) {

      // Assigns the new version code to versionCodeOverride, which changes the
      // version code for only the output APK, not for the variant itself. Skipping
      // this step causes Gradle to use the value of variant.versionCode for the APK.
      output.versionCodeOverride =
              baseAbiVersionCode * 1000 + variant.versionCode
    }
  }
}

Kotlin

android {
  ...
  defaultConfig {
    ...
    versionCode = 4
  }
  splits {
    ...
  }
}

// Map for the version code that gives each ABI a value.
val abiCodes = mapOf("armeabi-v7a" to 1, "x86" to 2, "x86_64" to 3)

// For per-density APKs, create a similar map:
// val densityCodes = mapOf("mdpi" to 1, "hdpi" to 2, "xhdpi" to 3)

import com.android.build.api.variant.FilterConfiguration.FilterType.*

// For each APK output variant, override versionCode with a combination of
// abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode
// is equal to defaultConfig.versionCode. If you configure product flavors that
// define their own versionCode, variant.versionCode uses that value instead.
androidComponents {
    onVariants { variant ->

        // Assigns a different version code for each output APK
        // other than the universal APK.
        variant.outputs.forEach { output ->
            val name = output.filters.find { it.filterType == ABI }?.identifier

            // Stores the value of abiCodes that is associated with the ABI for this variant.
            val baseAbiCode = abiCodes[name]
            // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes,
            // the following code doesn't override the version code for universal APKs.
            // However, because you want universal APKs to have the lowest version code,
            // this outcome is desirable.
            if (baseAbiCode != null) {
                // Assigns the new version code to output.versionCode, which changes the version code
                // for only the output APK, not for the variant itself.
                output.versionCode.set(baseAbiCode * 1000 + (output.versionCode.get() ?: 0))
            }
        }
    }
}

Per altri esempi di schemi di codici di versione alternativi, consulta Assegnare i codici di versione.

Creare più APK

Dopo aver configurato il file build.gradle o build.gradle.kts a livello di modulo per compilare più APK, fai clic su Compila > Compila APK per compilare tutti gli APK per il modulo attualmente selezionato nel riquadro Progetto. Gradle crea gli APK per ogni densità o ABI nella directory build/outputs/apk/ del progetto.

Gradle genera un APK per ogni densità o ABI per cui configuri più APK. Se attivi più APK sia per le densità che per gli ABI, Gradle crea un APK per ogni combinazione di densità e ABI.

Ad esempio, lo snippet build.gradle riportato di seguito consente di creare più APK per le densità mdpi e hdpi, nonché per le ABI x86 e x86_64:

Groovy

...
  splits {
    density {
      enable true
      reset()
      include "mdpi", "hdpi"
    }
    abi {
      enable true
      reset()
      include "x86", "x86_64"
    }
  }

Kotlin

...
  splits {
    density {
      isEnable = true
      reset()
      include("mdpi", "hdpi")
    }
    abi {
      isEnable = true
      reset()
      include("x86", "x86_64")
    }
  }

L'output della configurazione di esempio include i seguenti quattro APK:

  • app-hdpiX86-release.apk: contiene codice e risorse per la densità hdpi e l'ABI x86.
  • app-hdpiX86_64-release.apk: contiene codice e risorse per la densità hdpi e l'ABI x86_64.
  • app-mdpiX86-release.apk: contiene codice e risorse per la densità mdpi e l'ABI x86.
  • app-mdpiX86_64-release.apk: contiene codice e risorse per la densità mdpi e l'ABI x86_64.

Quando crei più APK in base alla densità dello schermo, Gradle genera sempre un APK universale che include codice e risorse per tutte le densità, oltre agli APK per densità.

Quando crei più APK in base all'ABI, Gradle genera un APK che include codice e risorse per tutti gli ABI solo se specifichi universalApk true nel blocco splits.abi del file build.gradle (per Groovy) o isUniversalApk = true nel blocco splits.abi del file build.gradle.kts (per lo script Kotlin).

Formato del nome del file APK

Quando viene eseguita la compilazione di più APK, Gradle genera i nomi dei file APK utilizzando il seguente schema:

modulename-screendensityABI-buildvariant.apk

I componenti dello schema sono:

modulename
Specifica il nome del modulo in fase di compilazione.
screendensity
Se sono attivati più APK per la densità dello schermo, specifica la densità dello schermo per l'APK, ad esempio mdpi.
ABI

Se sono abilitati più APK per l'ABI, specifica l'ABI per l'APK, ad esempio x86.

Se sono abilitati più APK sia per la densità dello schermo sia per l'ABI, Gradle concatena il nome della densità con il nome dell'ABI, ad esempio mdpiX86. Se universalApk è abilitato per gli APK per ABI, Gradle utilizza universal come parte dell'ABI del nome del file dell'APK universale.

buildvariant
Specifica la variante di build in fase di creazione, ad esempio debug.

Ad esempio, quando crei l'APK per la densità dello schermo mdpi per la versione di debug di myApp, il nome del file APK è myApp-mdpi-debug.apk. La versione di release di myApp configurata per creare più APK sia per la densità dello schermo mdpi sia per l'ABI x86 ha il nome file APK myApp-mdpiX86-release.apk.