Longos tempos de compilação atrasam o processo de desenvolvimento. Nesta página, vamos apresentar algumas técnicas para ajudar a resolver gargalos de velocidade de build.
O processo geral para melhorar a velocidade de build do app é este:
- Otimizar a configuração do build realizando etapas que beneficiam imediatamente a maioria dos projetos do Android Studio.
- Criar um perfil para seu build para identificar e diagnosticar alguns dos gargalos mais complicados que podem ser específicos do projeto ou da estação de trabalho.
Sempre que possível, implemente o app que você está desenvolvendo em um dispositivo com o Android 7.0 (nível 24 da API) ou uma versão mais recente. Versões mais recentes da Plataforma Android oferecem recursos melhores para enviar atualizações ao app, como o Android Runtime (ART) e o suporte nativo para vários arquivos DEX.
Observação: depois de lançar o primeiro build limpo, você vai perceber que os builds seguintes (limpos e incrementais) vão apresentar uma performance muito mais rápida, mesmo sem usar as otimizações descritas nesta página. Isso ocorre porque o daemon do Gradle tem um período de “aquecimento” para aumento de desempenho, semelhante a outros processos da JVM.
Otimizar a configuração do build
Siga estas dicas para aumentar a velocidade de build do seu projeto do Android Studio.
Manter suas ferramentas atualizadas
As ferramentas do Android recebem otimizações de build e novos recursos em quase todas as atualizações. Algumas das dicas nesta página presumem que você está usando a versão mais recente. Para aproveitar as otimizações mais recentes, mantenha estes itens atualizados:
Usar KSP em vez do kapt
A ferramenta de processamento de anotações (kapt, na sigla em inglês) do Kotlin é significativamente mais lenta que o Kotlin KSP. Se você estiver escrevendo código-fonte em Kotlin com anotações e usando ferramentas que processa anotações (como o Room) com suporte à KSP, migre para a KSP.
Evitar a compilação de recursos desnecessários
Evite compilar e empacotar recursos que não estejam sendo testados, como localizações de idiomas extras e recursos de densidade de tela. Em vez disso, especifique apenas um recurso de idioma e uma densidade de tela para a variação "dev", como mostrado no exemplo abaixo:
Groovy
android { ... productFlavors { dev { ... // The following configuration limits the "dev" flavor to using // English stringresources and xxhdpi screen-density resources. resourceConfigurations "en", "xxhdpi" } ... } }
Kotlin
android { ... productFlavors { create("dev") { ... // The following configuration limits the "dev" flavor to using // English stringresources and xxhdpi screen-density resources. resourceConfigurations("en", "xxhdpi") } ... } }
Tentar colocar o Portal do plug-in do Gradle por último
No Android, todos os plug-ins são encontrados nos repositórios google()
e
mavenCentral()
. No entanto, seu build pode
precisar de plug-ins de terceiros que são resolvidos usando o
serviço
gradlePluginPortal()
.
O Gradle pesquisa os repositórios na ordem em que são declarados.
Portanto, o desempenho do build é melhorado quando os repositórios listados primeiro contêm
a maioria dos plug-ins. Por esse motivo, experimente colocar a entrada
gradlePluginPortal()
por último no bloco do repositório do arquivo
settings.gradle
. Na maioria dos casos, isso minimiza o número de pesquisas de plug-ins redundantes e
melhora a velocidade do build.
Para ver mais informações sobre como o Gradle navega em vários repositórios, consulte Como declarar vários repositórios na documentação do Gradle.
Usar valores de configuração do build estáticos com seu build de depuração
Sempre use valores estáticos para propriedades que acessam o arquivo do manifesto ou os arquivos de recursos para descobrir o tipo de build de depuração.
O uso de códigos de versão dinâmicos, nomes de versão, recursos ou qualquer outra lógica de build que mude o arquivo de manifesto exige um build de app completo sempre que você quiser implementar uma mudança, mesmo que ela precise apenas de um hot swap. Caso sua configuração de build exija essas propriedades dinâmicas, isole-as nas suas variantes de build de lançamento e mantenha os valores estáticos para os builds de depuração, conforme mostrado no exemplo abaixo.
... // Use a filter to apply onVariants() to a subset of the variants. onVariants(selector().withBuildType("release")) { variant -> // Because an app module can have multiple outputs when using multi-APK, versionCode // is only available on the variant output. // Gather the output when we are in single mode and there is no multi-APK. val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE } // Create the version code generating task. val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) { it.outputFile.set(project.layout.buildDirectory.file("versionCode${variant.name}.txt")) } // Wire the version code from the task output. // map will create a lazy Provider that: // 1. Runs just before the consumer(s), ensuring that the producer (VersionCodeTask) has run // and therefore the file is created. // 2. Contains task dependency information so that the consumer(s) run after the producer. mainOutput.versionCode.set(versionCodeTask.flatMap { it.outputFile.map { it.asFile.readText().toInt() } }) } ... abstract class VersionCodeTask : DefaultTask() { @get:OutputFile abstract val outputFile: RegularFileProperty @TaskAction fun action() { outputFile.get().asFile.writeText("1.1.1") } }
Consulte o roteiro setVersionsFromTask no GitHub para aprender a definir um código de versão dinâmico no seu projeto.
Usar versões de dependência estáticas
Ao declarar dependências nos arquivos build.gradle
, evite usar números de versão
dinâmicos (com um sinal de soma no fim, como 'com.android.tools.build:gradle:2.+'
).
O uso de números de versão dinâmicos pode causar atualizações inesperadas, dificuldade para resolver diferenças entre
versões e builds mais lentos, causados pelo Gradle ao verificar se há atualizações.
Portanto, use números de versão estáticos.
Criar módulos de biblioteca
Procure no seu app um código que possa ser convertido em um módulo de biblioteca do Android. Modularizar o código dessa maneira permite que o sistema compile somente os módulos que você modificar e armazene em cache essas saídas para builds futuros. A modularização também faz com que a execução de projetos paralelos (link em inglês) seja mais eficaz quando essa otimização é ativada.
Criar tarefas para lógica de build personalizada
Depois de criar um perfil para seu build, se ele
mostrar que uma parte relativamente longa do tempo de build é gasta na fase **Configuring
Projects**, analise os scripts build.gradle
e procure
um código para incluir em uma tarefa personalizada do Gradle. Quando alguma lógica de build
é movida para uma tarefa, é importante garantir que a tarefa seja executada somente quando necessário, que os resultados possam ser armazenados em cache para
builds futuros e que essa lógica de build possa ser executada em paralelo se você ativar a execução de projeto em paralelo (link em inglês). Para saber mais sobre as tarefas para lógica de build
personalizado, leia a documentação oficial do Gradle (link em inglês).
Dica: caso seu build inclua um grande número de tarefas personalizadas,
organize seus arquivos build.gradle
criando classes de tarefas personalizadas (link em inglês). Adicione as classes ao
diretório project-root/buildSrc/src/main/groovy/
.
O Gradle as inclui automaticamente no caminho de classe de todos
os arquivos build.gradle
do projeto.
Converter imagens em WebP
O WebP é um formato de arquivo de imagem que oferece compactação com perda (como JPEG) e transparência (como PNG), mas com mais qualidade do que JPEG ou PNG.
A redução dos tamanhos de arquivos de imagem, sem que seja necessário compactar o tempo de build, pode agilizar os builds, principalmente se o app usa muitos recursos de imagem. Entretanto, você poderá perceber um pequeno aumento no uso de CPU do dispositivo ao descompactar as imagens WebP. Use o Android Studio para converter as imagens em WebP com facilidade.
Desativar o processamento de PNG
Mesmo que você não converta as imagens PNG em WebP, ainda é possível agilizar o build desativando a compactação automática de imagens sempre que o app for criado.
No plug-in do Android 3.0.0
ou versões mais recentes, por padrão, o processamento de PNG é desativado somente para o tipo de build de "depuração". Para desativar essa
otimização para outros tipos de build, adicione o código abaixo ao arquivo build.gradle
:
Groovy
android { buildTypes { release { // Disables PNG crunching for the "release" build type. crunchPngs false } } }
Kotlin
android { buildTypes { getByName("release") { // Disables PNG crunching for the "release" build type. isCrunchPngs = false } } }
Como tipos de build ou variações de produto não definem essa propriedade, é necessário
definir a propriedade manualmente para true
durante a criação da versão
de lançamento do app.
Testar o coletor de lixo em paralelo da JVM
A performance do build pode ser melhorada configurando o coletor de lixo otimizado da JVM usado pelo Gradle. Enquanto o JDK 8 é configurado para usar o coletor de lixo em paralelo por padrão, o JDK 9 e versões mais recentes são configurados para usar o coletor de lixo G1 (link em inglês).
Para potencialmente melhorar o desempenho do build, recomendamos que você
teste seus builds do Gradle com o coletor
de lixo em paralelo. Em gradle.properties
, defina:
org.gradle.jvmargs=-XX:+UseParallelGC
Se já houver outras opções definidas nesse campo, adicione uma nova opção:
org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC
Para medir a velocidade do build com diferentes configurações, consulte Criar perfil para seu build.
Aumentar o tamanho de heap da JVM
Se houver builds lentos e, principalmente, se os resultados do
Build Analyzer
mostrarem que a coleta de lixo levou mais de 15% do tempo de build,
aumente o tamanho de heap da Java Virtual Machine (JVM).
No arquivo gradle.properties
, defina o limite como 4, 6 ou 8 gigabytes,
conforme mostrado no exemplo abaixo:
org.gradle.jvmargs=-Xmx6g
Em seguida, faça um teste para conferir se a velocidade de build melhorou. A maneira mais fácil de determinar o tamanho ideal de heap é aumentar um pouco o limite e, em seguida, testar se houve uma melhoria suficiente na velocidade de build.
Caso o coletor de lixo em paralelo da JVM seja utilizado, a linha inteira vai ficar assim:
org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g
Para analisar os erros de memória da JVM, ative a flag HeapDumpOnOutOfMemoryError (link em inglês). Com isso, a JVM gera um heap dump quando o sistema fica sem memória.
Usar classes R não transitivas
Use as classes R
não transitivas para builds mais rápidos
em apps com vários módulos. Isso ajuda a evitar
a duplicação de recursos, garantindo que a classe R
de cada módulo contenha apenas referências aos próprios recursos,
sem extrair referências das dependências. Assim, os builds ficam mais rápidos
e você evita a recompilação. Esse é o comportamento padrão no Plug-in do Android para Gradle 8.0.0 e versões mais recentes.
A partir do Android Studio Bumblebee, as classes R
não transitivas são ativadas por padrão para novos projetos.
Você pode atualizar projetos criados em versões anteriores do Android Studio para usar classes R
não transitivas.
Para isso, acesse Refactor > Migrate to Non-Transitive R Classes.
Para saber mais sobre os recursos de app e a classe R
, consulte a
Visão geral dos recursos de aplicativo.
Usar classes R não constantes
Usar a classe R
não constante
campos em apps e testes para melhorar a incrementabilidade da compilação Java
e permitir uma redução mais precisa de recursos. Campos da classe R
não são constantes para as bibliotecas, já que os recursos são numerados
ao empacotar o APK para o app ou teste que depende dessa biblioteca.
Esse é o comportamento padrão no Plug-in do Android para Gradle 8.0.0 e versões mais recentes.
Desativar a flag do Jetifier
Como a maioria dos projetos usa bibliotecas AndroidX diretamente, você pode remover a flag
Jetifier para melhorar a performance do build. Para remover
a flag Jetifier, defina android.enableJetifier=false
no
arquivo gradle.properties
.
O Build Analyzer pode fazer uma verificação para definir se a flag pode ser removida com segurança para permitir que o projeto tenha um build com melhor performance e possa ser migrado das bibliotecas de Suporte do Android descontinuadas. Para saber mais sobre o Build Analyzer, consulte Resolver problemas de desempenho do build.
Usar o cache de configuração
A cache de configuração permite que o Gradle registre informações sobre o gráfico de tarefas de build e as reutilize em builds subsequentes. O Gradle não precisa reconfigurar todo o build novamente.
Para ativar o cache de configuração, siga estas etapas:
- Verifique se todos os plug-ins do projeto são compatíveis.
Use o Build Analyzer para verificar se o projeto oferece suporte ao cache de configuração. O Build Analyzer executa uma sequência de builds de teste para determinar se o recurso pode ser ativado no projeto. Consulte o problema 13490 (link em inglês) para acessar uma lista de plug-ins com suporte.
Adicione o seguinte código ao arquivo
gradle.properties
:org.gradle.configuration-cache=true # Use this flag carefully, in case some of the plugins are not fully compatible. org.gradle.configuration-cache.problems=warn
Quando o cache de configuração estiver ativado, a saída do build será exibida na primeira execução do projeto
diz Calculating task graph as no configuration cache is available for tasks
. Durante
execuções subsequentes, a saída do build vai informar Reusing configuration cache
.
Para saber mais sobre o cache de configuração, consulte a postagem do blog Análise aprofundada do armazenamento da configuração em cache e a documentação do Gradle sobre o cache de configuração (links em inglês).
Problemas de cache de configuração introduzidos no Gradle 8.1 e no Plug-in do Android para Gradle 8.1
O cache de configuração se tornou estável no Gradle 8.1 e introduziu a API de arquivos
monitoramento. Chamadas como File.exists()
, File.isDirectory()
e File.list()
são gravadas pelo
Gradle para rastrear arquivos de entrada de configuração.
O Plug-in do Android para Gradle (AGP) 8.1 usa essas APIs File
para alguns arquivos que o Gradle precisa.
não são entradas de cache. Isso aciona uma invalidação de cache adicional quando usado com
Gradle 8.1 e mais recentes, diminuindo a velocidade do desempenho do build.
Os elementos a seguir são tratados como entradas de cache no AGP 8.1:
Entrada | Issue Tracker | Corrigido em |
$GRADLE_USER_HOME/android/FakeDependency.jar | Problema 289232054 | AGP 8.2. |
saída do cmake | Problema 287676077 | AGP 8.2. |
$GRADLE_USER_HOME/.android/analytics.settings | Problema 278767328 | AGP 8.3. |
Se você usa essas APIs ou um plug-in com elas, pode haver uma regressão no tempo de build, porque algumas lógicas de build usando essas APIs pode acionar a invalidação adicional do cache. Consulte Melhorias no rastreamento de entrada da configuração do build para conferir uma discussão sobre esses padrões e como corrigir a lógica de compilação ou desativar temporariamente o o rastreamento da API de arquivos.