Siga as práticas recomendadas

Ao trabalhar com regras de retenção, é importante alcançar o nível certo de especificidade para garantir que você veja benefícios e mantenha o comportamento do app. Consulte as seções a seguir para saber mais sobre bons padrões e o que evitar nas regras de retenção.

Padrões adequados nas regras de retenção

As regras de retenção bem definidas são o mais específicas possível:

  • Para a especificação de classe, sempre especifique 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 keep. Isso cria um link 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.annotation usam 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 por que partes do código são preservadas. Por exemplo, use @DisplayComponent em um app em que os componentes de exibição exigem que algumas partes sejam mantidas.

  • Sempre que possível, a especificação do membro precisa ser declarada, e apenas referenciar as partes da classe que precisam ser mantidas para o funcionamento do app. 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 preservaçã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 permanência em um pacote, defina uma regra de permanência, conforme mostrado no exemplo a seguir:

-keepclassmembers class com.example.pkg.** { *; }

O que deve ser evitado

A sintaxe da regra de permanência tem muitas opções, mas para benefícios de desempenho sustentáveis e mensuráveis, recomendamos não usar o seguinte:

  • Evite usar o operador de inversão ! em regras de manutenção, porque você pode aplicar uma regra sem querer a quase todas as classes no seu aplicativo.
  • Não use regras de manutenção em todo o pacote, como -keep class com.example.pkg.** { *; }, a longo prazo. Eles podem ser usados 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.

Se não for possível seguir essas regras, talvez você esteja usando muita reflexão aberta. Nesse caso, evite a reflexão ou a biblioteca usando reflexão. Consulte o estudo de caso do Gson.