Se o app tiver definido o minSdk
da API 20 ou anterior, e o app e as
bibliotecas a que ele faz referência excederem 65.536 métodos, você vai encontrar erro de build abaixo, que
indica que o app atingiu o limite da arquitetura de build do Android:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
Versões anteriores do sistema de build relatam um erro diferente, que indica o mesmo problema:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
Essas condições de erro mostram um número em comum: 65.536. Esse número representa o total de referências que podem ser invocadas pelo código em um único arquivo de bytecode Dalvik Executable (DEX). Esta página explica como superar essa limitação, ativando uma configuração de app denominada multidex, que permite que o app crie e leia vários arquivos DEX.
Sobre o limite de 64 K referências
Arquivos de apps Android (APK) contêm arquivos de bytecode executáveis no formato Dalvik Executable (DEX), que contêm o código compilado usado para executar o app. A especificação do Dalvik Executable limita o total de métodos que podem ser referenciados em um único arquivo DEX a 65.536. Isso inclui métodos de framework do Android, métodos de biblioteca e métodos do seu próprio código.
No contexto da ciência da computação, o termo Kilo, ou K (link em inglês), denota 1.024 (ou 2^10). Como 65.536 equivale a 64 X 1.024, esse limite é chamado de "limite de 64 K referências".Suporte a multidex para o Android 5.0 e versões anteriores
Versões da plataforma anteriores ao Android 5.0 (API de nível 21) usam o tempo de execução Dalvik para executar o código do app. Por padrão, o Dalvik limita os apps a um único
arquivo de bytecode classes.dex
por APK. Para contornar essa
limitação, adicione a biblioteca multidex ao arquivo build.gradle
ou
build.gradle.kts
do módulo:
Groovy
dependencies { def multidex_version = "2.0.1" implementation "androidx.multidex:multidex:$multidex_version" }
Kotlin
dependencies { val multidex_version = "2.0.1" implementation("androidx.multidex:multidex:$multidex_version") }
Essa biblioteca se torna parte do arquivo DEX principal do app e, em seguida, gerencia o acesso aos outros arquivos DEX e ao código que eles contêm. Para conferir as versões atuais dessa biblioteca, consulte versões multidex.
Para saber mais, consulte a seção sobre como configurar seu app para multidex.Suporte a multidex para Android 5.0 e versões mais recentes
O Android 5.0 (nível 21 da API) e versões mais recentes usam um ambiente de execução conhecido como ART que
oferece suporte nativo ao carregamento de vários arquivos DEX de arquivos APK. O ART
executa a pré-compilação durante a instalação do app, verificando se há
arquivos classesN.dex
e os compilando em um único
arquivo OAT para
execução no dispositivo Android. Portanto, se a minSdkVersion
for 21 ou mais recente, o multidex fica ativado por padrão, e a biblioteca multidex não é necessária.
Para saber mais sobre o ambiente de execução do Android 5.0, leia Android Runtime (ART) e Dalvik.
Observação: quando você executa seu app usando o Android Studio, o build é otimizado para seus dispositivos de destino. Isso inclui a ativação de multidex quando os dispositivos de destino estiverem executando o Android 5.0 e versões mais recentes. Como essa otimização é aplicada somente ao implantar seu app usando o Android Studio, talvez seja necessário configurar seu build de lançamento para multidex para contornar o limite de 64.000 métodos.
Evitar o limite de 64.000 métodos
Antes de configurar seu app para permitir o uso de 64.000 ou mais referências a métodos, reduza o número total de referências chamadas pelo código do seu app, incluindo métodos definidos pelo código do app ou pelas bibliotecas incluídas.
As estratégias abaixo podem ajudar a não atingir o limite de referências do DEX:
- Analisar as dependências diretas e transitivas do app
- Avalie se o valor de qualquer dependência de biblioteca grande incluída no app excede a quantidade de código adicionada. Um padrão comum, mas problemático, é incluir uma biblioteca muito grande porque alguns métodos utilitários foram úteis. Muitas vezes, a redução das dependências de código do app pode ajudar a evitar o limite de referências do DEX.
- Remover código não utilizado com o R8
- Ative a redução de código para executar o R8 nos builds de lançamento. Ative a redução para garantir que você não esteja enviando códigos não utilizados com os APKs. Se a redução estiver configurada corretamente, ela também vai remover códigos e recursos não utilizados das dependências.
O uso dessas técnicas pode diminuir o tamanho geral do seu APK e evitar a necessidade de multidex no seu app.
Configurar o app para multidex
Observação: se aminSdkVersion
for definida como 21 ou uma versão mais recente, o multidex ficará ativado por padrão,
e a biblioteca multidex não será necessária.
Caso a minSdkVersion
esteja definida como 20 ou anterior, use a
biblioteca multidex e faça
as modificações abaixo no projeto do seu app:
-
Modifique o arquivo
build.gradle
de nível de módulo para ativar o multidex e adicionar a biblioteca multidex como dependência, conforme mostrado aqui:Groovy
android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 33 multiDexEnabled true } ... } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
Kotlin
android { defaultConfig { ... minSdk = 15 targetSdk = 33 multiDexEnabled = true } ... } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
- Dependendo de você modificar ou não a classe
Application
, execute uma das seguintes ações:Se você não substituir a classe
Application
, edite o arquivo de manifesto para definirandroid:name
na tag<application>
desta maneira:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application android:name="androidx.multidex.MultiDexApplication" > ... </application> </manifest>
Se você substituir a classe
Application
, mude-a para estenderMultiDexApplication
desta maneira:Kotlin
class MyApplication : MultiDexApplication() {...}
Java
public class MyApplication extends MultiDexApplication { ... }
Se você substituir a classe
Application
, mas não puder mudar a classe base, substitua o métodoattachBaseContext()
e a chamadaMultiDex.install(this)
para ativar o multidex:Kotlin
class MyApplication : SomeOtherApplication() { override fun attachBaseContext(base: Context) { super.attachBaseContext(base) MultiDex.install(this) } }
Java
public class MyApplication extends SomeOtherApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
Cuidado: não execute
MultiDex.install()
ou qualquer outro código por reflexão ou JNI antes da conclusão deMultiDex.install()
. O rastreio multidex não seguirá essas chamadas, causando umaClassNotFoundException
ou erros de verificação devido a uma partição de classe inválida entre arquivos DEX.
Agora, ao criar o app, as ferramentas de compilação do Android construirão um arquivo DEX principal (classes.dex
) e arquivos DEX de apoio (classes2.dex
, classes3.dex
e assim por diante), conforme necessário.
Em seguida, o sistema de build vai empacotar todos os arquivos DEX no APK.
Durante a execução, em vez de pesquisar apenas o arquivo
classes.dex
principal, as APIs multidex usam um carregador de classes especial para pesquisar todos os
arquivos DEX disponíveis para os métodos.
Limitações da biblioteca multidex
A biblioteca multidex tem algumas limitações conhecidas. Ao incorporar a biblioteca à configuração do build do app, considere o seguinte:
- A instalação de arquivos DEX durante a inicialização na partição de dados de um dispositivo é complexa e poderá resultar em erros "O app não está respondendo" (ANR) se os arquivos DEX secundários forem grandes. Para evitar esse problema, ative a redução de código para diminuir o tamanho dos arquivos DEX e remover as partes não utilizadas do código.
- Quando executado em versões anteriores ao Android 5.0 (nível 21 da API), o uso
de multidex não é suficiente para contornar o limite linearalloc (problema 37008143). Esse limite aumentou no
Android 4.0 (nível 14 da API), mas isso não resolveu o problema completamente.
Em versões anteriores ao Android 4.0, é possível atingir o limite linearalloc antes de atingir o limite de índice do DEX. Se você estiver destinando o app a níveis de API anteriores ao 14, faça um teste completo nessas versões da plataforma, uma vez que o app poderá ter problemas na inicialização ou quando determinados grupos de classes forem carregados.
A redução de código pode diminuir ou possivelmente eliminar esses problemas.
Declarar as classes necessárias no arquivo DEX principal
Ao criar cada arquivo DEX de um app multidex, as ferramentas de compilação tomam decisões complexas para determinar as classes necessárias no arquivo DEX principal, para que o app seja iniciado corretamente. Se alguma classe necessária
para a inicialização não for fornecida no arquivo DEX principal, o app falhará
apresentando o erro java.lang.NoClassDefFoundError
.
As ferramentas de build reconhecem os caminhos de código acessados diretamente no código do app. No entanto, esse problema pode ocorrer quando os caminhos do código estão menos visíveis, por exemplo, quando uma biblioteca que você usa tem dependências complexas. Por exemplo, se o código utiliza introspecção ou invocação de métodos Java no código nativo, essas classes talvez não sejam reconhecidas como necessárias no arquivo DEX principal.
Se você receber java.lang.NoClassDefFoundError
,
especifique manualmente as classes extras necessárias no arquivo DEX
principal, declarando-as com a propriedade multiDexKeepProguard
no seu tipo de build. Se há uma classe associada no
arquivo multiDexKeepProguard
, ela
é adicionada ao arquivo DEX principal.
Propriedade multiDexKeepProguard
O arquivo multiDexKeepProguard
usa o mesmo formato do ProGuard e oferece suporte à
toda a gramática do ProGuard. Para saber mais sobre como personalizar o que é mantido no app, consulte
Personalizar o código a ser mantido.
O arquivo que você especificar em multiDexKeepProguard
precisará conter opções de -keep
em qualquer sintaxe válida do ProGuard. Por exemplo: -keep com.example.MyClass.class
. Você pode criar um arquivo chamado multidex-config.pro
como o seguinte:
-keep class com.example.MyClass -keep class com.example.MyClassToo
Ou, se você quiser especificar todas as classes de um pacote, o arquivo ficará assim:
-keep class com.example.** { *; } // All classes in the com.example package
Em seguida, você pode declarar esse arquivo para um tipo de build desta forma:
Groovy
android { buildTypes { release { multiDexKeepProguard file('multidex-config.pro') ... } } }
Kotlin
android { buildTypes { getByName("release") { multiDexKeepProguard = file("multidex-config.pro") ... } } }
Otimizar o multidex em builds de desenvolvimento
Configurações de multidex exigem um tempo de processamento de compilação significativamente maior, porque o sistema de compilação precisa tomar decisões complexas sobre quais classes precisam ser incluídas no arquivo DEX principal e quais delas podem ser incluídas nos arquivos DEX secundários. Isso significa que builds incrementais que utilizam multidex costumam ser mais demorados e podem atrasar o processo de desenvolvimento.
Para reduzir os tempos de build incremental mais longos, use
a pré-dexação para reutilizar a saída multidex entre builds.
A pré-dexação utiliza um formato ART disponível apenas no Android 5.0 (nível 21 da API) ou versões mais recentes. Se você está usando o Android Studio, o ambiente de desenvolvimento integrado utiliza a pré-dexação automaticamente
ao implantar o app em um dispositivo com Android 5.0 (nível 21 da API) ou versão mais recente.
No entanto, se você está executando os builds do Gradle na linha de comando, é necessário definir o
minSdkVersion
como 21 ou uma versão mais recente para ativar a pré-dexação.
minSdkVersion
,
conforme mostrado:
Groovy
android { defaultConfig { ... multiDexEnabled true // The default minimum API level you want to support. minSdkVersion 15 } productFlavors { // Includes settings you want to keep only while developing your app. dev { // Enables pre-dexing for command-line builds. When using // Android Studio 2.3 or higher, the IDE enables pre-dexing // when deploying your app to a device running Android 5.0 // (API level 21) or higher, regardless of minSdkVersion. minSdkVersion 21 } prod { // If you've configured the defaultConfig block for the production version of // your app, you can leave this block empty and Gradle uses configurations in // the defaultConfig block instead. You still need to include this flavor. // Otherwise, all variants use the "dev" flavor configurations. } } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
Kotlin
android { defaultConfig { ... multiDexEnabled = true // The default minimum API level you want to support. minSdk = 15 } productFlavors { // Includes settings you want to keep only while developing your app. create("dev") { // Enables pre-dexing for command-line builds. When using // Android Studio 2.3 or higher, the IDE enables pre-dexing // when deploying your app to a device running Android 5.0 // (API level 21) or higher, regardless of minSdkVersion. minSdk = 21 } create("prod") { // If you've configured the defaultConfig block for the production version of // your app, you can leave this block empty and Gradle uses configurations in // the defaultConfig block instead. You still need to include this flavor. // Otherwise, all variants use the "dev" flavor configurations. } } buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } } } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
Para aprender outras estratégias para melhorar as velocidades de build (seja no Android Studio ou na linha de comando), leia Otimizar a velocidade do seu build. Para saber mais sobre o uso de variantes de build, consulte Configurar variações de versão.
Dica: se você tem variantes de build diferentes para diferentes
necessidades de multidex, pode fornecer um arquivo de manifesto específico para cada
variante, de modo que somente o arquivo da API de nível 20 e anteriores mude o
nome da tag <application>
. Também é possível
criar uma subclasse Application
diferente para cada variante, de modo que
somente a subclasse para a API de nível 20 e anteriores estenda a classe MultiDexApplication
ou
chame MultiDex.install(this)
.
Testar apps multidex
Ao criar testes de instrumentação para apps multidex, nenhuma outra configuração é necessária
se você usa uma
instrumentação
MonitoringInstrumentation
(ou
AndroidJUnitRunner
). Se você usar outra
Instrumentation
,
substitua o método onCreate()
por este código:
Kotlin
fun onCreate(arguments: Bundle) { MultiDex.install(targetContext) super.onCreate(arguments) ... }
Java
public void onCreate(Bundle arguments) { MultiDex.install(getTargetContext()); super.onCreate(arguments); ... }