Otimizar a velocidade do seu build

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Longos tempos de compilação atrasam o processo de desenvolvimento. Esta página oferece algumas técnicas para ajudar você a resolver os gargalos de velocidade de compilação.

O processo geral para melhorar sua velocidade de compilação é o seguinte:

  1. Otimizar a configuração do build realizando etapas que beneficiam imediatamente a maioria dos projetos do Android Studio.
  2. 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.

Ao desenvolver seu app, você precisa implantá-lo em um dispositivo com o Android 7.0 (API de nível 24) ou uma versão mais recente, sempre que possível. Versões mais recentes da plataforma Android implementam maneiras melhores para enviar atualizações ao app, como o Android Runtime (ART) e a compatibilidade nativa com vários arquivos DEX.

Observação: depois do seu primeiro build limpo, você perceberá que os subsequentes (limpos e incrementais) têm um desempenho muito mais rápido, mesmo sem o uso de qualquer uma das 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 criação 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 os seguintes itens atualizados:

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). Você pode fazer isso especificando apenas um recurso de idioma e uma densidade de tela para a variação “dev”, como mostrado no exemplo a seguir:

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 isso, teste a entrada gradlePluginPortal() a colocando 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 de compilação estáticos com seu build de depuração

Sempre use valores estáticos/codificados para propriedades que acessam o arquivo do manifesto ou os arquivos de recursos para seu tipo de build de depuração.

Por exemplo, 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 uma criação de app completa sempre que você quer executar uma mudança, mesmo que ela precise apenas de um hot swap. Se a sua configuração de build exigir 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. Para ver um exemplo, consulte o arquivo build.gradle abaixo.

Groovy

int MILLIS_IN_MINUTE = 1000 * 60
int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE

android {
    ...
    defaultConfig {
        // Making either of these two values dynamic in the defaultConfig will
        // require a full app build and reinstallation because the AndroidManifest.xml
        // must be updated.
        versionCode 1
        versionName "1.0"
        ...
    }

    // The defaultConfig values above are fixed, so your incremental builds don't
    // need to rebuild the manifest (and therefore the whole app, slowing build times).
    // But for release builds, it's okay. So the following script iterates through
    // all the known variants, finds those that are "release" build types, and
    // changes those properties to something dynamic.
    applicationVariants.all { variant ->
        if (variant.buildType.name == "release") {
            variant.mergedFlavor.versionCode = minutesSinceEpoch;
            variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName;
        }
    }
}

Kotlin

val MILLIS_IN_MINUTE = 1000 * 60
val minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE

android {
    ...
    defaultConfig {
        // Making either of these two values dynamic in the defaultConfig will
        // require a full app build and reinstallation because the AndroidManifest.xml
        // must be updated.
        versionCode = 1
        versionName = "1.0"
        ...
    }

    // The defaultConfig values above are fixed, so your incremental builds don't
    // need to rebuild the manifest (and therefore the whole app, slowing build times).
    // But for release builds, it's okay. So the following script iterates through
    // all the known variants, finds those that are "release" build types, and
    // changes those properties to something dynamic.
    applicationVariants.forEach { variant ->
        if (variant.buildType.name == "release") {
            variant.mergedFlavor.versionCode = minutesSinceEpoch
            variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName
        }
    }
}

Usar versões de dependência estáticas

Quando você declarar dependências nos seus arquivos build.gradle, evite o uso de números de versão com um sinal de soma no final, 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 de versão e builds mais lentos causados pelo Gradle ao verificar se há atualizações. Em vez disso, use números de versão estáticos/codificados.

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. Isso também torna a execução de projetos paralelos (link em inglês) mais eficaz quando essa otimização é ativada.

Criar tarefas para lógica de compilação personalizada

Depois que você criar um perfil de compilação, se ele mostrar que uma parte relativamente grande do tempo de compilação é passada na fase “Configuring Projects”, analise os scripts build.gradle e procure um código que possa ser incluído em uma tarefa personalizada do Gradle. Quando alguma lógica de compilação é movida para uma tarefa, ela é executada somente quando necessário. Os resultados podem ser armazenados em cache para builds futuros, e essa lógica de compilação se qualificará para execução em paralelo se você ativar a execução de projeto em paralelo (link em inglês). Para saber mais, 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 suas classes ao diretório project-root/buildSrc/src/main/groovy/. O Gradle vai incluí-las automaticamente no caminho de classe de todos os arquivos build.gradle do seu projeto.

Converter imagens em WebP

WebP (link em inglês) é um formato de arquivo de imagem que proporciona 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 precisar realizar compactação do tempo de compilação, pode agilizar seus 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. É fácil converter as imagens em WebP usando o Android Studio.

Desativar o processamento de PNG

Se você não puder (ou não quiser) converter suas imagens PNG em WebP, ainda será possível agilizar seu build desativando a compactação automática de imagens sempre que criar seu app. Caso esteja usando o plug-in do Android 3.0.0 ou versão mais recente, o processamento de PNG estará desativado por padrão somente para o tipo de build de "depuração". Para desativar essa otimização para outros tipos de build, adicione o seguinte ao seu 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.

Configurar o coletor de lixo da JVM

O desempenho do build pode ser melhorado 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 do G1.

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.

Usar classes R não transitivas

Use as classes R não transitivas para conseguir ter builds mais rápidos em aplicativos 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.

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

Desativar a sinalização do Jetifier

A maioria dos projetos usa bibliotecas AndroidX de forma direta, então você pode remover a sinalização do Jetifier para melhorar a performance do build. Para remover a verificação do Jetifier, defina android.enableJetifier=false no arquivo gradle.properties. O Build Analyzer pode verificar se a sinalização pode ser removida de forma segura para permitir que o projeto tenha uma melhor performance de build e migre das Bibliotecas de Suporte do Android descontinuadas. Para saber mais sobre o Build Analyzer, consulte Resolver problemas de performance do build.

Usar o armazenamento de configuração em cache (experimental)

O armazenamento de configuração em cache é um recurso experimental que permite que o Gradle registre informações sobre o gráfico de tarefas de build e as reutilize em builds subsequentes. Assim, não é necessário configurar o build inteiro novamente. Para ativar o armazenamento da configuração em cache, siga estas etapas:

  1. Verifique se todos os plug-ins do projeto são compatíveis. Use o Build Analyzer para verificar se o projeto é compatível com o armazenamento da configuração em cache. Ele executa uma sequência de builds de testes para determinar se o recurso pode ser ativado no projeto. Você também pode consultar o problema 13490 para ver uma lista de plug-ins com suporte.
  2. Adicione o seguinte código ao arquivo gradle.properties:

      org.gradle.unsafe.configuration-cache=true
      # Use this flag sparingly, in case some of the plugins are not fully compatible
      org.gradle.unsafe.configuration-cache-problems=warn

  3. Quando o armazenamento da configuração em cache estiver ativado, a saída do build terá a mensagem Calculating task graph as no configuration cache is available for tasks na primeira execução do projeto. Durante as execuções subsequentes, a saída do build vai mostrar a mensagem Reusing configuration cache.
Para saber mais sobre o armazenamento da configuração em cache, consulte a postagem do blog Análise aprofundada do armazenamento da configuração em cache e a documentação do Gradle sobre armazenamento da configuração em cache (links em inglês).