Ao trabalhar com regras de retenção, é importante acertar a especificidade para garantir que você se beneficie delas e mantenha o app funcionando corretamente. Consulte as seções a seguir para saber mais sobre bons padrões e o que evitar.
Padrões adequados nas regras de retenção
As regras de retenção devem ser o mais específicas possível:
Sempre estabeleça uma classe, classe base ou classe anotada específica, se possível, conforme mostrado nos exemplos a seguir:
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }Sempre que possível, use anotações no código-fonte (como uma anotação
@Keep) e segmente essas anotações diretamente nas regras de retenção. Isso cria um vínculo claro e explícito entre seu código e as regras que o preservam, tornando sua configuração mais robusta, fácil de entender e menos propensa a falhas quando o código muda.Por exemplo, bibliotecas como
androidx.annotationusam este padrão:// In your source code @Keep class MyDataClass { /* ... */ } // In your R8 rules -keep @androidx.annotation.DisplayComponent class * {*;}Recomendamos nomear as anotações de forma que elas forneçam um contexto significativo sobre o motivo de partes do código serem preservadas. Por exemplo, use
@DisplayComponentem um app em que os componentes de exibição exigem que algumas partes sejam mantidas.Sempre que possível, a especificação do membro deve ser declarada, e apenas as partes da classe que precisarem ser mantidas para o funcionamento do app devem ser referenciadas. Recomendamos não aplicar uma regra a uma classe inteira definindo o escopo de membro opcional como
{ *; }, a menos que seja estritamente necessário.-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }Se você usar a opção global
repackageclasses, evite especificar o nome do pacote opcional. Isso resulta em arquivos DEX menores porque o prefixo do pacote é omitido nos nomes de classe reempacotados.
Se não for possível seguir essas diretrizes, isole temporariamente o código que precisa ser mantido em um pacote dedicado e aplique a regra de retenção a ele. No entanto, essa não é uma solução de longo prazo. Para saber mais, consulte Adotar otimizações de forma incremental. Para usar uma regra de retenção em um pacote, defina-a conforme mostrado no exemplo a seguir:
-keepclassmembers class com.example.pkg.** { *; }
O que deve ser evitado
A sintaxe da regra de retenção tem muitas opções, mas para ter benefícios de desempenho sustentáveis e mensuráveis, recomendamos não usar o seguinte:
- Não use regras de retenção em todo o pacote, como
-keep class com.example.pkg.** { *; }, a longo prazo. Elas podem ser usadas temporariamente para resolver problemas ao configurar o R8. Para mais informações, consulte Limitar o escopo da otimização. Em geral, tenha cuidado com os caracteres curinga. Mantenha apenas o código necessário. - Quando possível, evite bibliotecas que sugerem copiar e colar regras de retenção ao usá-las, especialmente as que se aplicam a todo o pacote. As bibliotecas projetadas para ter um bom desempenho no Android devem evitar a reflexão sempre que possível e incorporar regras de retenção para consumidores quando necessário.
- Evite usar o operador de inversão
!em regras de retenção, porque você pode acabar aplicando uma regra a quase todas as classes no seu aplicativo sem querer.
Se não for possível seguir essas regras, talvez você esteja usando muitas reflexões abertas. Nesse caso, evite-as ou evite a biblioteca que usa reflexão. Consulte o estudo de caso do Gson.