Usar o analisador de configuração do R8

O R8 Configuration Analyzer é uma ferramenta projetada para ajudar você a maximizar os benefícios de desempenho do R8, fornecendo insights detalhados sobre a qualidade da configuração do app. Ele permite rastrear e melhorar a otimização do R8 monitorando métricas importantes, especificamente pontuações de redução, otimização e ofuscação, que indicam a porcentagem da base de código disponível para otimização. Ao identificar regras de manutenção amplas ou desnecessárias, incluindo aquelas introduzidas por bibliotecas de terceiros, o analisador ajuda você a refinar sua configuração para garantir que o R8 possa otimizar o máximo possível de classes, campos e métodos.

Gerar o relatório

Com o AGP 9.3.0 e versões mais recentes, é possível gerar o relatório do R8 Configuration Analyzer usando uma tarefa independente dedicada do Gradle ou automaticamente durante um build do R8.

Executar a tarefa independente do Gradle (recomendado para uso local)

Ao iterar ativamente nas regras de manutenção, use a tarefa independente do Gradle para avaliar rapidamente o impacto das mudanças sem criar totalmente o APK ou o pacote:

./gradlew :app:analyzeReleaseR8Config

Como essa tarefa ignora a geração de APKs ou pacotes, ela oferece um ciclo de feedback muito mais curto. Assim, você pode analisar rapidamente como suas regras de manutenção afetam as pontuações de redução, otimização e ofuscação e refiná-las imediatamente. O relatório HTML é gerado em app/build/reports/r8/r8-config-analyzer-release.html.

Gerar automaticamente durante builds regulares

Ao executar um build de lançamento completo do R8 (como assembleRelease), o relatório é gerado automaticamente em build/outputs/mapping/release/configanalyzer.html. Para desativar a geração automática de saídas durante builds regulares, defina a seguinte propriedade do Gradle:

android.experimental.r8.enableR8ConfigurationAnalyzer=false

Para AGP 9.2 e versões anteriores

Para AGP 9.2 e versões anteriores, defina a propriedade do sistema com.android.tools.r8.dumpkeepradiushtmltodirectory ao executar uma tarefa do Gradle com um build ativado com o R8.

./gradlew assembleRelease \
    -Dcom.android.tools.r8.dumpkeepradiushtmltodirectory=<output_directory>

Por exemplo, use o comando a seguir para gerar o relatório HTML no diretório /tmp/r8analysis:

# To create the /tmp/r8analysis folder.
mkdir -p /tmp/r8analysis

# To generate the report in the /tmp/r8analysis folder.
./gradlew assembleRelease \
    -Dcom.android.tools.r8.dumpkeepradiushtmltodirectory=/tmp/r8analysis

Entender o relatório

O R8 Configuration Analyzer fornece insights sobre a configuração do R8 do seu app e o impacto de cada regra de manutenção no app. Isso ajuda você a alcançar a otimização máxima do R8, melhorando o desempenho do app. Use as pontuações a seguir para entender quanto da sua base de código está disponível para otimização pelo R8.

Exemplo da seção de resumo do relatório
Figura 1. Exemplo da seção de resumo do relatório.

Pontuação de redução

Quando o R8 reduz seu app, ele diminui o tamanho geral identificando e eliminando códigos e recursos não utilizados, garantindo que o build final seja o mais enxuto possível. A pontuação de redução acompanha a porcentagem de classes, campos e métodos sujeitos a redução. Por exemplo, uma pontuação de redução de 66% significa que o R8 pode realizar a redução em 66% da sua base de código.

Pontuação de otimização

O R8 realiza otimizações, como inlining de métodos e mesclagem de classes, o que resulta em melhorias de inicialização e memória para seu app. A pontuação de otimização acompanha a porcentagem de classes, campos e métodos sujeitos a otimizações do R8. Por exemplo, se a pontuação de otimização for de 66%, isso significa que o R8 só poderá realizar a otimização em 66% da sua base de código.

Pontuação de ofuscação

Ao ofuscar classes, campos e métodos em nomes mais curtos, o R8 reduz o uso de metadados do app para economizar memória. A pontuação de ofuscação mede a porcentagem de código disponível para ofuscação na sua base de código.

Refinar regras de retenção

Para melhorar as pontuações e desbloquear uma otimização melhor do R8, refine as regras de manutenção para que elas não impeçam desnecessariamente o R8 de otimizar seu app. Mantenha apenas classes, métodos ou campos acessados usando reflexão.

Para isso, use a Análise de regras de retenção.

Exemplo da análise de regra de permanência
Figura 2. Um exemplo da análise de regra de permanência.

Para ver a análise detalhada de uma regra, clique nela para abrir a tela de detalhes.

Exemplo da análise de regra de permanência
Figura 3. Um exemplo da análise de regra de permanência.

Como refinar regras de retenção

Para refinar suas regras de retenção e aproveitar todo o potencial das otimizações do R8 para seu app, faça o seguinte:

  1. Para cada regra de manutenção, confira a porcentagem de classes, campos e métodos que não podem ser otimizados pelo R8 no Configuration Analyzer. Use isso para identificar as regras de preservação que impedem a otimização em um grande número de classes, campos ou métodos. As propriedades de otimização impedidas por cada regra de permanência também são listadas.
  2. Se você encontrar uma regra de preservação que esteja impedindo a otimização de um grande número de classes, verifique quais classes, campos e métodos estão sendo impedidos de otimização por essa regra para saber se ela está preservando itens que não são invocados dinamicamente usando reflexão.
  3. Reduza a otimização bloqueada pelas regras de permanência segmentando apenas as classes, os campos ou os métodos necessários escolhendo a opção de permanência certa e seguindo as práticas recomendadas.
  4. Investigue e execute testes que cubram as classes, os campos e os métodos afetados da regra de permanência e refine as regras de permanência.

Inspecionar a otimização de bibliotecas

Ao integrar bibliotecas de terceiros, elas geralmente incluem as próprias regras de preservação do consumidor para trabalhar com o R8. Como o autor da biblioteca não pode prever sua implementação específica, às vezes ele escreve regras conservadoras e abrangentes que impedem a otimização em mais classes, campos e métodos do que o necessário. Isso pode impedir que o R8 otimize partes do app que não têm nada a ver com a execução real da biblioteca em tempo de execução. Use o R8 Configuration Analyzer para identificar bibliotecas que introduzem regras que afetam negativamente a otimização do seu app.

Use o analisador de configuração para inspecionar o efeito combinado de todas as regras de preservação do consumidor mescladas. Ao analisar o impacto de cada regra de permanência de uma biblioteca de terceiros, é possível identificar e rastrear as bibliotecas específicas que impedem uma grande quantidade de otimização no seu app.

Como otimizar bibliotecas

Para resolver regras de manutenção introduzidas por bibliotecas de terceiros, faça o seguinte:

  • Se uma biblioteca incluir uma regra muito ampla, recomendamos entrar em contato com o responsável pela manutenção da biblioteca com os dados do seu relatório para demonstrar como as regras atuais afetam as pontuações de otimização do seu app. Se for uma biblioteca externa, procure bugs nela antes de registrar problemas.
  • Se necessário, teste possíveis melhorias filtrando regras de uma biblioteca específica. Você pode importar as regras da biblioteca para seu projeto, excluir as gerais e executar novamente o analisador de configuração para medir os possíveis ganhos em tamanho e performance.

Regras subsumidas

Pode haver casos em que várias regras de retenção se sobrepõem, e uma delas pode estar impedindo mais otimização do que o necessário. Se houver duas regras de manutenção na sua base de código.

# Prevents optimization in the entire package
# Remove this to improve optimization
-keep class com.example.package.** { *; }

# Prevents optimization to the class inside the package
-keep class com.example.package.Myclass

A primeira regra de preservação, que impede a otimização em todo o pacote, subsume a segunda, que tem como destino uma classe dentro do pacote preservado pela primeira regra. Quando as regras de preservação se sobrepõem, uma pode bloquear mais otimizações do que o necessário. Ao refinar essas regras conflitantes, você pode maximizar a otimização do R8 e eliminar a dívida técnica. Esse processo envolve simplificar sua configuração para garantir que apenas o código essencial seja mantido e aproveitar todo o potencial dos recursos de otimização do R8.

Exemplo da seção de resumo do relatório
Figura 4. Exemplo de regras subsumidas no relatório.

Otimizar regras subsumidas

  1. Encontre as regras de manutenção de subsunção usando o R8 Configuration Analyzer.
  2. Identifique as classes, os campos ou os métodos exatos na sua base de código que dependem da reflexão, que precisa ser mantida usando regras keep. Isso ajuda a refinar as regras de retenção.
  3. Usando o analisador de configuração, compare o impacto de cada regra que tem como destino as mesmas classes, campos ou métodos. Você pode usar a porcentagem de otimização evitada por cada regra de permanência para identificar qual é mais ampla e qual é mais restrita.
    1. Se a regra restrita for escrita com precisão, mantendo apenas os membros ou classes exatos que são acessados de forma reflexiva, remova a regra de manutenção mais ampla. Isso desbloqueia com segurança as otimizações do R8 para o restante do pacote.
    2. Se a regra geral estiver segmentando as classes certas, mantenha-a e exclua a regra específica. A regra restrita é apenas um excesso redundante. Refine a regra geral para segmentar apenas classes, campos ou métodos que você identificou.

Verifique e teste suas mudanças: execute o analisador de configuração novamente para garantir que o conflito foi corrigido. Em seguida, compile um build de lançamento e teste suas mudanças para garantir que a base de código funcione como esperado.

Remover regras desnecessárias

Com o analisador de configuração, é possível auditar sistematicamente a base de código para identificar e remover regras de manutenção obsoletas que poluem sua configuração. O analisador de configuração do R8 destaca especificamente duas fontes principais de regras desnecessárias:

  • Regras não usadas: regras que correspondem a zero classes, métodos ou campos no build atual. Elas geralmente persistem após a refatoração de código, a remoção de dependências ou configurações de cópia e colar que não são mais relevantes, adicionando complexidade de configuração desnecessária.
  • Regras idênticas: regras de preservação idênticas são aquelas que têm como destino as mesmas classes, campos e métodos ou declarações duplicadas de regras de preservação no mesmo arquivo ou em arquivos diferentes.

Os dois tipos de regras adicionam confusão à sua configuração, dificultando a manutenção e a depuração. Ao identificar esses itens, você pode limpar sua configuração.