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.
Bons padrões em regras de retenção
As regras de retenção bem definidas são o mais específicas possível e seguem estes padrões:
Para a especificação de classe, sempre especifique uma classe, classe de 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 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, o snippet a seguir demonstra como manter a classe MyClass, bem como outras classes anotadas com
@com.example.DisplayComponent:// In the source code @com.example.DisplayComponent class MyClass { /* ... */ } // In the keep rules -keep @com.example.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
repackageclassesopção global, evite especificar o nome do pacote opcional. Isso resulta em arquivos DEX menores porque o prefixo do pacote é omitido nos nomes de classe reempacotados.Mantenha as regras de retenção para todos os itens acessados por reflexão. Mesmo que esses itens sejam mantidos pelo R8 sem regras de retenção explícitas, manter as regras reais é fundamental, porque mudanças futuras no código podem fazer com que o R8 não retenha mais esses itens.
Para reflexão no seu próprio código, use Jetpack Keep para gerar regras de retenção mais fáceis de manter. Cada anotação está no código que realiza a reflexão. Portanto, quando você muda esse código, atualiza ou remove a anotação no mesmo lugar. Dessa forma, as regras não preservam o código que seu app não reflete mais. O Lint também sinaliza chamadas reflexivas que não são anotadas.
Sempre que possível, use
-assumenosideeffectsou-convertchecknotnullpara otimizar as verificações de nulo, porque isso pode reduzir significativamente o tamanho do DEX do app. Para mais informações, consulte Tipos de regra adicionais.
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.