Desenvolver vários APKs

Se você publicar seu aplicativo no Google Play, precisará criar e fazer upload de um Android App Bundle. Quando você fizer isso, o Google Play gerará e exibirá automaticamente APKs otimizados para a configuração do dispositivo de cada usuário, para que eles façam o download apenas do código e dos recursos necessários para executar seu aplicativo. A publicação de vários APKs é útil se você não for publicar no Google Play, mas será preciso criar, assinar e gerenciar cada APK por conta própria.

Embora seja recomendável criar um único APK para oferecer compatibilidade com todos os seus dispositivos de destino sempre que possível, isso pode resultar em um APK muito grande devido aos arquivos necessários para que haja compatibilidade com várias densidades de tela ou interfaces binárias de aplicações (ABIs, na sigla em inglês). Uma maneira de reduzir o tamanho do seu APK é criar vários APKs que contenham arquivos para densidades de tela ou ABIs específicas.

O Gradle pode criar APKs separados que contenham apenas código e recursos específicos para cada densidade ou ABI. Esta página descreve como configurar sua compilação para gerar vários APKs. Se você precisar criar versões diferentes do aplicativo que não sejam baseadas na densidade de tela ou na ABI, poderá usar variantes de compilação.

Configurar a compilação para vários APKs

Para configurar sua compilação para vários APKs, adicione um bloco splits ao arquivo build.gradle do módulo. Dentro do bloco splits, forneça um bloco density que especifique como o Gradle gerará APKs por densidade ou um bloco abi que especifique como o Gradle gerará APKs por ABI. Você pode fornecer blocos de densidade e ABI, e o sistema de compilação criará um APK para cada combinação de densidade e ABI.

Configurar vários APKs para densidades de tela

Para criar APKs separados para diferentes densidades de tela, adicione um bloco density ao bloco splits. No bloco density, forneça uma lista de densidades de tela desejadas e dos tamanhos de tela compatíveis. A lista de tamanhos de tela compatíveis só precisará ser usada se forem necessários elementos <compatible-screens> específicos no manifesto de cada APK.

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

enable
Se você definir este elemento como true, o Gradle gerará vários APKs com base nas densidades de tela definidas. O valor padrão é false.
exclude
Especifica uma lista de densidades separadas por vírgulas para as quais o Gradle não precisa gerar APKs separados. Use exclude se você quiser gerar APKs para a maioria das densidades, mas precisar excluir algumas densidades incompatíveis com seu aplicativo.
reset()
Apaga a lista padrão de densidades de tela. Use somente quando combinado com o elemento include para especificar as densidades que você quer adicionar. O snippet a seguir define a lista de densidades como apenas ldpi e xxhdpi chamando reset() para apagar a lista e, em seguida, usando include.
    reset()  // Clears the default list from all densities to no densities.
    include "ldpi", "xxhdpi" // Specifies the two densities we want to generate APKs for.
    
include
Especifica uma lista de densidades separadas por vírgulas para as quais o Gradle precisa gerar APKs. Use somente em combinação com reset() para especificar uma lista exata de densidades.
compatibleScreens
Especifica uma lista separada por vírgulas de tamanhos de tela compatíveis. Esta configuração injeta um nó <compatible-screens> correspondente no manifesto de cada APK. Isso oferece uma maneira conveniente de gerenciar as densidades de tela e os tamanhos de tela na mesma seção build.gradle. No entanto, o uso de <compatible-screens> pode limitar os tipos de dispositivos com os quais seu aplicativo funcionará. Para conhecer outras formas de compatibilidade com diferentes tamanhos de tela, consulte Compatibilidade com várias telas.

Como cada APK que é baseado na densidade da tela inclui uma tag <compatible-screens> com restrições específicas sobre os tipos de tela com que o APK é compatível, mesmo que você publique vários APKs, alguns dispositivos novos não corresponderão aos vários filtros do APK. Assim, o Gradle sempre gera um APK universal adicional que contém recursos para todas as densidades de tela e não inclui uma tag <compatible-screens>. Você precisa publicar esse APK universal junto com seus APKs por densidade para fornecer um substituto para dispositivos que não correspondam aos APKs com uma tag <compatible-screens>.

O exemplo a seguir gera um APK separado para cada densidade de tela listada em Conjunto de telas compatíveis, exceto ldpi, xxhdpi e xxxhdpi. Isso é feito usando exclude para remover três densidades da lista padrão de densidades.

    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 Gradle should not create multiple APKs for.
          exclude "ldpi", "xxhdpi", "xxxhdpi"

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

Para acessar uma lista de nomes de densidade e de tamanho de tela, consulte Como oferecer compatibilidade com várias telas. Para mais detalhes sobre como distribuir seu aplicativo para tipos de tela e dispositivos específicos, consulte Distribuição para telas específicas.

Configurar vários APKs para ABIs

Para criar APKs separados para diferentes ABIs, adicione um bloco abi ao bloco splits. No bloco abi, forneça uma lista de ABIs desejadas.

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

enable
Se você definir este elemento como true, o Gradle gerará vários APKs com base nas ABIs definidas. O valor padrão é false.
exclude
Especifica uma lista de ABIs separadas por vírgulas para as quais o Gradle não precisa gerar APKs separados. Use exclude se você quiser gerar APKs para a maioria das ABIs, mas precisar excluir algumas que não são compatíveis com seu aplicativo.
reset()
Apaga 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 apagar 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 de ABIs separadas por vírgulas para as quais o Gradle precisa gerar APKs. Use somente em combinação com reset() para especificar uma lista exata de ABIs.
universalApk
Se for true, o Gradle 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 APK. O valor padrão é false. Esta opção só está disponível no bloco splits.abi. Ao criar vários APKs com base na densidade da tela, o Gradle sempre gera um APK universal que contém código e recursos para todas as densidades de tela.

O exemplo a seguir gera um APK separado para cada ABI: x86 e x86_64. Isso é feito usando reset() para iniciar com uma lista vazia de ABIs, seguida de include com uma lista de ABIs que receberão um APK.

    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 we only
          // want APKs for x86 and x86_64.

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

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

          // Specifies that we do not want to also generate a universal APK that includes all ABIs.
          universalApk false
        }
      }
    }
    

Consulte ABIs compatíveis para ver uma lista de quais são compatíveis.

mips, mips64 e armeabi

O plug-in do Android para Gradle 3.1.0 e posteriores não geram mais APKs para as seguintes ABIs por padrão: mips, mips64 e armeabi. Isso porque o NDK r17 e posteriores não incluem mais essas ABIs como destinos compatíveis.

Primeiro, verifique no Google Play Console se há usuários fazendo o download de APKs do seu aplicativo voltados a essas ABIs. Se não houver, omita-os da sua compilação. Se você quiser continuar criando APKs voltados para essas ABIs, precisará usar o NDK r16b ou anterior e especificar as ABIs no arquivo build.gradle, como mostrado abaixo:

    splits {
        abi {
            include 'armeabi', 'mips', 'mips64'
            ...
        }
    }
    

Problema conhecido: se você estiver usando o plug-in do Android para Gradle 3.0.1 ou anterior com o NDK r17 ou posterior, poderá ver o seguinte erro: Error:ABIs [mips64, armeabi, mips] are not supported for platform.. Isso ocorre porque as versões mais antigas do plug-in ainda incluem as ABIs não compatíveis por padrão quando você cria APKs por ABI. Para resolver esse problema, atualize para a versão mais recente do plug-in ou, no arquivo build.gradle do seu aplicativo, redefina a lista padrão de ABIs do plug-in e inclua apenas as ABIs compatíveis que você quer, conforme mostrado abaixo:

    ...
    splits {
        abi {
            ...
            reset()
            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
        }
    }
    

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 do módulo. Como a Google Play Store não permite que o mesmo app tenha vários APKs com as mesmas informações de versão, você precisa garantir que cada APK tenha o próprio versionCode antes de fazer upload para a Play Store.

Você pode configurar o arquivo build.gradle do módulo para substituir o versionCode de cada APK. Ao criar um mapeamento que atribua um valor numérico exclusivo para cada ABI e densidade para as quais vários APKs são configurados, você poderá substituir o código da versão de saída por um valor que combine o código de versão definido no bloco defaultConfig ou productFlavors com o valor numérico atribuído à densidade ou ABI.

No exemplo a seguir, o APK para a ABI x86 teria um versionCode de 2.004 e a ABI x86_64 teria 3.004. A atribuição de códigos de versão em grandes incrementos, como 1.000, permite atribuir códigos de versão exclusivos, se você precisar atualizar seu aplicativo. Por exemplo, se defaultConfig.versionCode for iterado como 5 em uma atualização subsequente, o Gradle atribuirá um versionCode de 2.005 ao APK x86 e de 3.005 ao APK x86_64.

Dica: se sua versão inclui um APK universal, atribua um versionCode que seja inferior ao de qualquer outro APK. Como a Google Play Store instala a versão do seu aplicativo que é compatível com o dispositivo de destino e tem o versionCode mais alto, atribuir um versionCode menor ao APK universal garante que a Google Play Store tente instalar um dos seus APKs antes de substituir pelo APK universal. O código de amostra abaixo lida com isso não substituindo o versionCode padrão de um APK universal.

    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 like this:
    // 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 does not override the version code for universal APKs.
        // However, because we 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 simply
          // causes Gradle to use the value of variant.versionCode for the APK.
          output.versionCodeOverride =
                  baseAbiVersionCode * 1000 + variant.versionCode
        }
      }
    }
    

Para ver mais exemplos de esquemas de código de versão alternativos, consulte Atribuição de códigos de versão.

Desenvolver vários APKs

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

O Gradle cria um APK para cada densidade ou ABI para as quais você configura vários APKs. Se você ativar vários APKs para densidades e ABIs, o Gradle criará um APK para cada combinação de densidade e ABI. Por exemplo, o snippet build.gradle a seguir permite criar vários APKs para densidades mdpi e hdpi, bem como para ABIs x86 e x86_64.

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

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

  • app-hdpiX86-release.apk: contém código e recursos apenas para densidade hdpi e ABI x86.
  • app-hdpiX86_64-release.apk: contém código e recursos apenas para densidade hdpi e ABI x86_64.
  • app-mdpiX86-release.apk: contém código e recursos apenas para densidade mdpi e ABI x86.
  • app-mdpiX86_64-release.apk: contém código e recursos apenas para densidade mdpi e ABI x86_64.

Ao criar vários APKs com base na densidade de tela, o Gradle sempre gera um APK universal que inclui código e recursos para todas as densidades de tela, além de APKs por densidade. Ao criar vários APKs baseados em ABI, o Gradle gera apenas um APK que inclui código e recursos para todas as ABIs se você especificar universalApk true no bloco splits.abi do arquivo build.gradle.

Formato de nome de arquivo do APK

Ao criar vários APKs, o Gradle usa nomes de arquivos do APK com o seguinte esquema:

modulename-screendensityABI-buildvariant.apk

Os componentes do esquema são:

modulename
Especifica o nome do módulo que está sendo criado.
screendensity
Se vários APKs para densidade de tela estão ativados, especifica a densidade da tela do APK, como "mdpi".
ABI
Se vários APKs para ABI estão ativados, especifica a ABI do APK, como "x86". Se vários APKs para densidade de tela e ABI estão ativados, o Gradle concatena o nome da densidade com o nome da ABI, por exemplo, "mdpiX86". Se universalApk for ativado para APKs por ABI, o Gradle usará "universal" como a parte da ABI do nome do arquivo do APK universal.
buildvariant
Especifica a variante de compilação que está sendo criada, como "debug".

Por exemplo, ao criar o APK de densidade de tela mdpi para a versão de depuração de "myApp", o nome do arquivo do APK será myApp-mdpi-debug.apk. A versão de lançamento do "myApp" configurada para criar vários APKs para a densidade da tela mdpi e a ABI x86 terá o nome de arquivo do APK myApp-mdpiX86-release.apk.