Otimização para autores de bibliotecas

Como autor de uma biblioteca, você precisa garantir que os desenvolvedores de apps possam incorporá-la facilmente ao app, mantendo uma experiência de usuário de alta qualidade. Verifique se a biblioteca é compatível com a otimização do Android sem configuração adicional ou documente que a biblioteca pode ser inadequada para uso no Android.

Esta documentação é destinada a desenvolvedores de bibliotecas publicadas, mas também pode ser útil para desenvolvedores de módulos de biblioteca interna em um app grande modularizado.

Se você é um desenvolvedor de apps e quer saber como otimizar seu app Android, consulte Ativar a otimização de apps. Para saber quais bibliotecas são adequadas para uso, consulte Escolher bibliotecas com sabedoria.

Usar a geração de código em vez da reflexão

Sempre que possível, use geração de código (codegen) em vez de reflexão. A geração de código e a reflexão são abordagens comuns para evitar códigos de texto clichê ao programar, mas a geração de código é mais compatível com um otimizador de apps como o R8:

  • Com a geração de código, o código é analisado e modificado durante o processo de build. Como não há modificações importantes após o tempo de compilação, o otimizador sabe qual código é necessário e o que pode ser removido com segurança.
  • Com a reflexão, o código é analisado e manipulado em tempo de execução. Como o código não é realmente finalizado até ser executado, o otimizador não sabe qual código pode ser removido com segurança. Ele provavelmente removerá o código usado dinamicamente por reflexão durante a execução, o que causa falhas no app para os usuários.

Muitas bibliotecas modernas usam a geração de código em vez da reflexão. Consulte KSP para conferir um ponto de entrada comum, usado por Room, Dagger2 e muitos outros.

Quando a reflexão é aceitável

Se você precisar usar a reflexão, reflita apenas em uma das seguintes opções:

  • Tipos segmentados específicos (implementadores de interface ou subclasses específicos)
  • Código usando uma anotação de tempo de execução específica

O uso da reflexão dessa maneira limita o custo de execução e permite a gravação de regras de manutenção de consumidores segmentados.

Essa forma específica e direcionada de reflexão é um padrão que pode ser encontrado no framework do Android (por exemplo, ao inflar atividades, visualizações e drawables) e nas bibliotecas do AndroidX (por exemplo, ao criar WorkManager ListenableWorkers ou RoomDatabases). Por outro lado, a reflexão aberta do Gson não é adequada para uso em apps Android.

Escrever regras de retenção do consumidor

As bibliotecas precisam empacotar regras de retenção "consumidor", que usam o mesmo formato das regras de retenção do app. Essas regras são agrupadas em artefatos de biblioteca (AARs ou JARs) e são consumidas automaticamente durante a otimização de apps Android quando a biblioteca é usada.

Bibliotecas AAR

Para adicionar regras de consumidor a uma biblioteca AAR, use a opção consumerProguardFiles no script de build do módulo da biblioteca Android. Para mais informações, consulte nossas orientações sobre como criar módulos de biblioteca.

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

Groovy

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

Bibliotecas JAR

Para agrupar regras com a biblioteca Kotlin/Java que é enviada como um JAR, coloque o arquivo de regras no diretório META-INF/proguard/ do JAR final, com qualquer nome de arquivo. Por exemplo, se o código estiver em <libraryroot>/src/main/kotlin, coloque um arquivo de regras do consumidor em <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro e as regras serão agrupadas no local correto no JAR de saída.

Verifique se o JAR final agrupa as regras corretamente verificando se elas estão no diretório META-INF/proguard.

Suporte a diferentes encolhedores (avançado)

É possível personalizar regras para que elas segmentem compressores específicos (R8 ou ProGuard), bem como versões específicas de compressores. Isso permite que a biblioteca funcione de maneira ideal em projetos que usam novas versões do compressor, permitindo que as regras atuais continuem sendo usadas em projetos com versões mais antigas do compressor.

Para especificar regras de redução direcionadas, é necessário incluí-las em locais específicos em uma biblioteca AAR ou JAR, conforme descrito abaixo.

In an AAR library:
    consumer-proguard-rules.pro (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

Isso significa que as regras de redução direcionadas são armazenadas no diretório META-INF/com.android.tools de um JAR ou no diretório META-INF/com.android.tools dentro do classes.jar de um AAR.

Nesse diretório, pode haver vários diretórios com nomes no formato de r8-from-<X>-upto-<Y> ou proguard-from-<X>-upto-<Y> para indicar para quais versões do encolhedor as regras dentro dos diretórios foram gravadas. As partes -from-<X> e -upto-<Y> são opcionais, a versão <Y> é exclusivo, e os intervalos de versão precisam ser contínuos.

Por exemplo, r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0 e r8-from-8.2.0 formam um conjunto válido de regras de redução direcionadas. As regras no diretório r8-from-8.0.0-upto-8.2.0 serão usadas pelo R8 da versão 8.0.0 até a exceto a versão 8.2.0.

Com essas informações, o Plug-in do Android para Gradle seleciona as regras dos diretórios R8 correspondentes. Se uma biblioteca não especificar regras de redução de tamanho, o plug-in do Android para Gradle vai selecionar as regras dos locais legados (proguard.txt para um AAR ou META-INF/proguard/<ProGuard-rules-file> para um JAR).