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 modo, 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 necessari per eseguire l'app. La pubblicazione di più APK è utile se pubblichi su uno store che non supporta il formato AAB. In questo caso, devi creare, firmare e gestire ogni APK autonomamente.

Anche se è preferibile creare un singolo APK per supportare tutti i dispositivi di destinazione ogni volta che è possibile, ciò potrebbe comportare un APK molto grande a causa dei file che supportano più Application Binary Interfaces (ABI). Un modo per ridurre le dimensioni dell'APK è creare più APK che contengano file per ABI specifiche.

Gradle può creare APK separati che contengono solo codice e risorse specifici per ogni ABI. Questa pagina descrive come configurare la build per generare più APK. Se devi creare versioni diverse della tua app che non si basano sull'ABI, utilizza invece le varianti di 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 abi che specifica come vuoi che Gradle generi gli APK per ABI.

Configurare più APK per gli 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 desiderate.

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

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 cui 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. Utilizza solo in combinazione con l'elemento include per specificare le ABI che vuoi aggiungere.

Il seguente snippet imposta l'elenco delle ABI solo su x86 e x86_64 chiamando reset() per cancellare 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 cui vuoi che Gradle generi APK. Utilizzare solo in combinazione con reset() per specificare un elenco esatto di ABI.
universalApk per Groovy o isUniversalApk per lo 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.

L'esempio seguente genera un APK separato per ogni ABI: x86 e x86_64. A questo scopo, utilizza reset() per iniziare con un elenco vuoto di ABI, seguito da include con un elenco di ABI per ognuna delle quali viene creato 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 delle ABI supportate, consulta ABI supportate.

Progetti senza codice nativo/C++

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

Il riquadro Crea varianti
Figura 1. Il pannello Crea varianti ha due colonne per i progetti senza codice nativo/C++.

Il valore Variante di build attiva per il modulo determina la variante di build di cui viene eseguito il deployment e che è visibile nell'editor. Per passare da una variante all'altra, fai clic sulla cella Variante di build attiva di un modulo e scegli la variante che preferisci dal campo dell'elenco.

Progetti con codice nativo/C++

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

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

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

Per modificare il tipo di build o l'ABI:

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

La modifica di una delle due colonne per un modulo dell'app o della libreria viene applicata a tutte le righe dipendenti.

Configurare il controllo delle versioni

Per impostazione predefinita, quando Gradle genera più APK, ognuno 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 tutti le stesse informazioni sulla versione, devi assicurarti che ogni APK abbia un versionCode univoco prima di caricarlo sul Play Store.

Puoi configurare il file build.gradle a livello di modulo per ignorare versionCode per ogni APK. Se crei una mappatura che assegna un valore numerico univoco a ogni ABI per cui configuri più APK, puoi sostituire il codice di versione di output con un valore che combina il codice di versione definito all'interno del blocco defaultConfig o productFlavors con il valore numerico assegnato all'ABI.

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

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

Suggerimento:se la build include un APK universale, assegnagli un versionCode inferiore a quello di tutti gli altri APK. Poiché Google Play Store installa la versione dell'app che è sia compatibile con il dispositivo di destinazione sia con il versionCode più alto, assegnando un versionCode inferiore all'APK universale si garantisce che Google Play Store tenti di installare uno degli APK prima di ripiegare sull'APK universale. Il seguente codice campione gestisce questo problema non eseguendo l'override del versionCode predefinito 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]

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)

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, vedi Assegnazione di codici di versione.

Creare più APK

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

Gradle crea un APK per ogni ABI per cui configuri più APK.

Ad esempio, il seguente snippet build.gradle consente di creare più APK per le ABI x86 e x86_64:

Groovy

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

Kotlin

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

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

  • app-X86-release.apk: Contiene codice e risorse per l'ABI x86.
  • app-X86_64-release.apk: Contiene codice e risorse per l'ABI x86_64.

Quando crei più APK in base all'ABI, Gradle genera un solo 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 del file build.gradle.kts (per Kotlin Script).

Formato del nome del file APK

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

modulename-ABI-buildvariant.apk

I componenti dello schema sono:

modulename
Specifica il nome del modulo in fase di creazione.
ABI

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

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