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. In questo caso, Google Play genera e pubblica automaticamente APK ottimizzati per la configurazione del dispositivo di ogni utente, in modo che gli utenti scarichino solo il codice e le risorse necessarie per eseguire la tua app. La pubblicazione di più APK è utile se pubblichi in uno store che non supporta il formato AAB. In questo caso, devi creare, firmare e gestire personalmente ogni APK.

Sebbene sia meglio creare un singolo APK per supportare tutti i dispositivi di destinazione, se possibile, ciò potrebbe generare un APK molto grande a causa dei file che supportano più densità di schermo o interfaccia utente binaria delle applicazioni (ABI). Un modo per ridurre le dimensioni dell'APK consiste nel creare più APK contenenti file per ABI o densità dello schermo specifiche.

Gradle può creare APK separati contenenti solo codice e risorse specifici di ogni densità o ABI. In questa pagina viene descritto come configurare la build per generare più APK. Se devi creare versioni diverse della tua app non basate sulla densità dello schermo o sull'ABI, utilizza invece le varianti della build.

Configurare la build per più APK

Per configurare la build 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 in che modo Gradle generi APK per densità o un blocco abi che specifichi la modalità di generazione degli APK per ABI da parte di Gradle. Puoi fornire blocchi sia per densità sia per ABI; il sistema di build crea un APK per ogni combinazione di densità e ABI.

Configurare più APK per le densità dello schermo

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

Le seguenti opzioni DSL 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 definite. Il valore predefinito è false.
exclude
Specifica un elenco di densità separate da virgole per cui non vuoi che Gradle generi APK separati. Utilizza exclude se vuoi generare APK per la maggior parte delle densità, ma devi escludere alcune densità non supportate dalla tua app.
reset()

Cancella l'elenco predefinito di densità dello schermo. Utilizzalo solo se combinato con l'elemento include per specificare le densità che vuoi aggiungere.

Lo snippet seguente imposta l'elenco di densità solo su ldpi e xxhdpi chiamando reset() per cancellare l'elenco, quindi 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 di densità separate da virgole per cui vuoi che Gradle generi gli APK. Utilizzala solo in combinazione con reset() per specificare un elenco esatto di densità.
compatibleScreens

Specifica un elenco separato da virgole di dimensioni dello schermo compatibili. Questa operazione inserisce un nodo <compatible-screens> corrispondente nel file manifest per ogni APK.

Questa impostazione consente di gestire facilmente 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 su cui funziona la tua app. Per conoscere modi alternativi per supportare schermi di diverse dimensioni, consulta la panoramica sulla compatibilità dello schermo.

Poiché ogni APK basato sulla densità dello schermo include un tag <compatible-screens> con limitazioni specifiche sui tipi di schermata supportati dall'APK, anche se pubblichi diversi APK, alcuni nuovi dispositivi non corrispondono ai diversi 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 in base alla densità per fornire un video di riserva per i dispositivi che non corrispondono agli APK con un tag <compatible-screens>.

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

Trendy

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 un elenco dei nomi delle densità e delle dimensioni dello schermo, consulta la sezione Supportare dimensioni dello schermo diverse. Per maggiori dettagli su come personalizzare diverse varianti di build della tua app per tipi di schermo e dispositivi specifici, consulta la pagina Dichiarare il supporto per schermo limitato.

Configurare più APK per le ABI

Per creare APK separati per ABI diverse, aggiungi un blocco abi all'interno del blocco splits. Nel blocco abi, fornisci un elenco delle ABI desiderate.

Per configurare più APK per ABI vengono utilizzate le seguenti opzioni DSL Gradle:

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

Cancella l'elenco predefinito di ABI. Utilizzalo solo se combinato con l'elemento include per specificare le ABI che vuoi aggiungere.

Lo snippet seguente imposta l'elenco di ABI solo su x86 e x86_64 chiamando reset() per cancellare l'elenco, quindi 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 le quali vuoi che Gradle generi gli APK. Utilizzala 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 ciascuna riceve un APK.

Trendy

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 delle ABI supportate, consulta la pagina ABI supportate.

Progetti senza codice nativo/C++

Per i progetti senza codice nativo/C++, il riquadro Genera varianti ha due colonne: Modulo e Variante build attiva, come mostrato nella Figura 1.

Riquadro delle varianti della build
Figura 1. Il riquadro Crea varianti ha due colonne per i progetti senza codice nativo/C++.

Il valore Variante build attiva per il modulo determina la variante build di cui viene eseguito il deployment e che è visibile nell'editor. Per passare da una variante all'altra, fai clic sulla cella Variante build 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 Genera varianti ha tre colonne: Modulo, Variante build attiva e ABI attiva, come mostrato nella Figura 2.

Figura 2. Il riquadro Crea varianti aggiunge la colonna ABI attiva per i progetti con codice nativo/C++.

Il valore Variante 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 attiva determina l'ABI utilizzata dall'editor, ma non influisce sugli elementi di cui viene eseguito il deployment.

Per modificare il tipo di build o ABI:

  1. Fai clic sulla cella della colonna Variante build attiva o ABI attiva.
  2. Scegli la variante o l'ABI desiderata nel campo dell'elenco. Viene eseguita automaticamente una nuova sincronizzazione.

La modifica di una colonna per un modulo dell'app o della libreria applica la modifica a tutte le righe dipendenti.

Configura 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 che hanno tutte le stesse informazioni sulla versione, devi assicurarti che ogni APK abbia un elemento versionCode univoco prima di caricarlo sul Play Store.

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

Nell'esempio seguente, l'APK dell'ABI x86 riceve un versionCode del 2004 e l'APK dell'ABI x86_64 riceve un valore versionCode di 3004.

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

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

Trendy

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.

Crea più APK

Dopo aver configurato il file build.gradle o build.gradle.kts a livello di modulo per creare più APK, fai clic su Crea > APK build per creare 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 crea un APK per ogni densità o ABI per cui configuri più APK. Se attivi più APK per densità e ABI, Gradle crea un APK per ogni combinazione di densità e ABI.

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

Trendy

...
  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 4 APK:

  • app-hdpiX86-release.apk: contiene codice e risorse per la densità di hdpi e l'ABI di x86.
  • app-hdpiX86_64-release.apk: contiene codice e risorse per la densità di hdpi e l'ABI di x86_64.
  • app-mdpiX86-release.apk: contiene codice e risorse per la densità di mdpi e l'ABI di x86.
  • app-mdpiX86_64-release.apk: contiene codice e risorse per la densità di mdpi e l'ABI di 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 basati su ABI, Gradle genera solo un APK che include codice e risorse per tutte le ABI, se specifichi universalApk true nel blocco splits.abi del file build.gradle (per Groovy) o isUniversalApk = true nel blocco splits.abi nel file build.gradle.kts (per lo script Kotlin).

Formato del nome del file APK

Quando crei più APK, Gradle genera i nomi file APK utilizzando il seguente schema:

modulename-screendensityABI-buildvariant.apk

I componenti dello schema sono:

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

Se sono attivati più APK per 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 ABI del nome file APK universale.

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

Ad esempio, durante la creazione di un APK di densità dello schermo mdpi per la versione di debug di myApp, il nome file dell'APK è myApp-mdpi-debug.apk. La versione di release di myApp configurata per creare più APK per la densità dello schermo mdpi e per l'ABI x86 ha un nome file APK myApp-mdpiX86-release.apk.