Desenvolver vários APKs

Embora seja melhor criar um único APK para oferecer suporte a todos os dispositivos de destino sempre que possível, isso pode resultar em um APK muito grande devido a arquivos que oferecem suporte a várias interfaces binárias do aplicativo (ABIs, na sigla em inglês). Uma maneira de reduzir o tamanho do APK é criar vários APKs que contenham arquivos para ABIs específicas.

O Gradle pode criar APKs separados que contenham apenas códigos e recursos específicos para cada ABI. Nesta página, descrevemos como configurar o build para gerar vários APKs. Caso precise criar versões diferentes do app que não sejam baseadas na ABI, use variantes de build.

Configurar o build para vários APKs

Para configurar o build para vários APKs, adicione um bloco splits ao arquivo build.gradle do módulo. No bloco splits, forneça um bloco abi que especifique como você quer que o Gradle gere APKs por ABI.

Configurar vários APKs para ABIs

Para criar APKs separados para ABIs diferentes, adicione um bloco abi dentro do bloco splits. No bloco abi, forneça uma lista das ABIs escolhidas.

As seguintes opções de DSL do Gradle são usadas para configurar vários APKs por ABI:

enable para Groovy ou isEnable para script Kotlin
Se você definir esse elemento como true, o Gradle vai gerar vários APKs com base nas ABIs definidas. O valor padrão é false.
exclude
Especifica uma lista separada por vírgulas de ABIs para as quais você não quer que o Gradle gere APKs separados. Use exclude caso queira gerar APKs para a maioria das ABIs, mas precise excluir algumas que não oferecem suporte ao seu app.
reset()

Limpa a lista padrão de ABIs. Use somente quando combinado com o elemento include para especificar as ABIs que você quer adicionar.

O snippet a seguir define a lista de ABIs como apenas x86 e x86_64 chamando reset() para limpar a lista e, em seguida, usando 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

Especifica uma lista separada por vírgulas de ABIs para que o Gradle gere APKs. Use apenas em combinação com reset() para especificar uma lista exata de ABIs.

universalApk para Groovy ou isUniversalApk para script Kotlin

Se for true, o Gradle vai gerar um APK universal, além de APKs por ABI. Um APK universal contém código e recursos para todas as ABIs em um único APK. O valor padrão é false.

O exemplo a seguir gera um APK separado para cada ABI: x86 e x86_64. Para isso, use reset() para começar com uma lista vazia de ABIs, seguida por include com uma lista de ABIs que recebem um APK cada.

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
    }
  }
}

Para ver uma lista de ABIs compatíveis, consulte ABIs compatíveis.

Projetos sem código nativo/C++

Para projetos sem código nativo/C++, o painel Build Variants tem duas colunas: Module e Active Build Variant, conforme mostrado na Figura 1.

O painel "Variantes de build" tem duas colunas para projetos sem código nativo/C++.
Figura 1. O painel Variantes de build tem duas colunas para projetos sem código nativo/C++.

O valor da Active Build Variant para o módulo determina a variante de build que é implantada e fica visível no editor. Para alternar entre variantes, clique na célula Variante de build ativa de um módulo e selecione a variante de build escolhida no campo de lista.

Projetos com código nativo/C++

Para projetos com código nativo/C++, o painel Build Variants tem três colunas: Module, Active Build Variant e Active ABI, conforme mostrado na Figura 2.

O painel "Variantes de build" adiciona a coluna "ABI ativa" para projetos com código nativo/C++.
Figura 2. O painel Variantes de build adiciona a coluna Active ABI para projetos com código nativo/C++.

O valor da Active Build Variant para o módulo determina a variante de build que é implantada e fica visível no editor. Para módulos nativos, o valor de Active ABI determina a ABI que o editor usa, mas não afeta o que é implantado.

Para mudar o tipo de build ou a ABI:

  1. Clique na célula da coluna variante de build ativa ou ABI ativa.
  2. Selecione a variante ou ABI escolhida no campo de lista. Uma nova sincronização é executada automaticamente.

Mudar uma coluna para um módulo de app ou de biblioteca aplica a mudança a todas as linhas dependentes.

Configurar o controle de versões

Por padrão, quando o Gradle gera vários APKs, cada um deles tem as mesmas informações de versão, conforme especificado no arquivo build.gradle ou build.gradle.kts do módulo. Como a Google Play Store não permite vários APKs para o mesmo app com as mesmas informações de versão, é necessário garantir que cada APK tenha um versionCode exclusivo antes de fazer upload deles para a Play Store.

É possível configurar o arquivo build.gradle do módulo para substituir o versionCode de cada APK. Ao criar um mapeamento que atribui um valor numérico exclusivo para cada ABI que você configura em vários APKs, é possível substituir o código de versão de saída por um valor que combina o código de versão definido no bloco defaultConfig ou productFlavors com o valor numérico atribuído à ABI.

No exemplo a seguir, o APK para a ABI x86 recebe um versionCode de 2004, e a ABI x86_64 recebe um versionCode de 3004.

Atribuir códigos de versão em grandes incrementos, como 1.000, permite que você atribua códigos de versão exclusivos posteriormente, se precisar atualizar o app. Por exemplo, se defaultConfig.versionCode iterar para 5 em uma atualização subsequente, o Gradle vai atribuir um versionCode de 2005 ao APK x86 e 3005 ao APK x86_64.

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))
            }
        }
    }
}

Para mais exemplos de esquemas de códigos de versão alternativos, consulte Atribuir códigos de versão.

Desenvolver vários APKs

Depois de configurar o arquivo build.gradle ou build.gradle.kts do módulo para criar vários APKs, clique em Build > Build APK para criar todos os APKs do módulo selecionado no painel Project. O Gradle cria os APKs para cada ABI no diretório build/outputs/apk/ do projeto.

O Gradle cria um APK para cada ABI que você configurar para vários APKs.

Por exemplo, o snippet build.gradle abaixo permite criar vários APKs para ABIs x86 e x86_64:

Groovy

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

Kotlin

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

O resultado da configuração de exemplo inclui os quatro APKs a seguir:

  • app-X86-release.apk: contém código e recursos para a ABI x86.
  • app-X86_64-release.apk: contém código e recursos para a ABI x86_64.

Ao criar vários APKs com base na ABI, o Gradle só gera um APK que inclui código e recursos para todas as ABIs se você especificar universalApk true no bloco splits.abi no arquivo build.gradle (para Groovy) ou isUniversalApk = true no bloco splits.abi no arquivo build.gradle.kts (para script Kotlin).

Formato de nome de arquivo do APK

Ao criar vários APKs, o Gradle gera nomes de arquivo usando o seguinte esquema:

modulename-ABI-buildvariant.apk

Os componentes do esquema são:

modulename
Especifica o nome do módulo que está sendo criado.
ABI
Se vários APKs para ABI estiverem ativados, especifica a ABI para o APK, como x86.
buildvariant
Especifica a variante de build que está sendo criada, por exemplo, debug.