Adicionar regras de manutenção

Quando você ativa a otimização de apps com as configurações padrão, o R8 realiza otimizações extensas para maximizar os benefícios de desempenho. O R8 faz modificações substanciais no código, incluindo renomeação, movimentação e remoção de campos e métodos de classes. Se isso causar erros, você precisará especificar quais partes do código devem ser deixadas em paz, escrevendo regras keep.

O R8 pode remover ou modificar o código incorretamente nas seguintes situações:

  • Reflexão: código acessado usando reflexão, por exemplo, usando Class.forName() ou Method.invoke(). O R8 geralmente não consegue informar quais classes ou métodos serão acessados dessa maneira.
  • Serialização: classes ou campos necessários para serialização e desserialização podem parecer não utilizados pelo R8 (essa é outra forma de reflexão).
  • Java Native Interface (JNI): métodos Java chamados pelo código nativo. O R8 não analisa o código nativo para saber o que ele pode chamar de volta no Java.

Esta página aborda como limitar a extensão das otimizações do R8. Para saber como personalizar quais recursos são mantidos, consulte Adicionar regras de manutenção de recursos.

Onde adicionar regras de manutenção

Adicione as regras a um arquivo proguard-rules.pro localizado no diretório raiz do módulo. O arquivo pode já estar lá, mas, se não estiver, crie-o. Para aplicar as regras no arquivo, declare-o no arquivo build.gradle.kts (ou build.gradle) no nível do módulo, conforme mostrado no código abaixo:

Kotlin

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true

            proguardFiles(
                // Default file with default optimization rules.
                getDefaultProguardFile("proguard-android-optimize.txt"),

                // File with your custom rules.
                "proguard-rules.pro"
            )
            ...
        }
    }
    ...
}

Groovy

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true

            proguardFiles(
                // Default file with default optimization rules.
                getDefaultProguardFile('proguard-android-optimize.txt'),

                // File with your custom rules.
                'proguard-rules.pro'
            )
        }
    }
    // ...
}

Por padrão, o script de build também inclui o arquivo proguard-android-optimize.txt. Esse arquivo inclui regras necessárias para a maioria dos projetos do Android. Portanto, mantenha-o no script de build.

Como escrever regras de manutenção

Durante a compilação do app, o R8 detecta qual código precisa ser mantido em um app analisando o gráfico de chamadas do app, que começa nas entradas do manifesto (como atividades ou serviços) e rastreia todas as chamadas de função de app e biblioteca. O R8 remove o código que não é referenciado diretamente dessa maneira, o que pode causar problemas se o código executado não fizer parte desse gráfico, por exemplo, código invocado por reflexão. Ao escrever suas próprias regras keep, você pode informar ao R8 o código que precisa permanecer no app.

Para adicionar uma regra de manutenção, adicione uma linha -keep no arquivo proguard-rules.pro.

Sintaxe de regra de manter

As regras de armazenamento geralmente seguem este formato:

-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]

Por exemplo, para preservar uma classe específica e todos os membros dela, use o seguinte:

-keep class com.myapp.MyClass { *; }

Para mais exemplos, consulte a seção de exemplos.

Confira o que os componentes da regra de manutenção fazem:

  • <KeepOption> permite especificar quais aspectos de uma classe preservar:

    Opção "Manter" Descrição

    -keep

    Preserve a classe e os membros listados em [{ OptionalMemberSpecification }].

    -keepclassmembers

    Permite a otimização da classe. Se a classe for preservada, os membros listados em [{ OptionalMemberSpecification }] também serão.

    -keepnames

    Permite a remoção de classes e membros, mas não ofusca ou modifica de outras maneiras.

    -keepclassmembernames

    Permita a remoção de classes e membros, mas não ofusque nem modifique membros de outras maneiras.

    -keepclasseswithmembers

    Não há remoção ou ofuscação de classes se os membros corresponderem ao padrão especificado.

    Recomendamos o uso de -keepclassmembers, já que ele permite a maioria dos otimizações, e depois -keepnames, se necessário. O -keep não permite otimizações. Portanto, use-o com moderação.

  • [OptionalModifier],...] permite listar zero ou mais modificadores de linguagem Java de uma classe, por exemplo, public ou final.

  • <ClassSpecification> permite especificar a qual classe (ou qual superclasse ou interface implementada) a regra de manutenção será aplicada. No caso mais simples, essa é uma classe totalmente qualificada.

  • [{ OptionalMemberSpecification }] permite filtrar o comportamento de retenção para apenas classes e métodos que correspondem a determinados padrões. Em geral, isso é recomendado na maioria das regras de retenção para evitar a retenção de mais itens do que o pretendido.

Exemplos de regras do Keep

Confira alguns exemplos de regras de manutenção bem projetadas.

Criar subclasse

Essa regra de manutenção é empacotada dentro de androidx.room:room-runtime para manter os construtores de banco de dados instanciados por reflexão.

-keep class * extends androidx.room.RoomDatabase { void <init>(); }

Reflexão do framework do Android ObjectAnimator

Essa regra de manutenção é empacotada dentro de androidx.vectordrawable:vectordrawable-animated para permitir que ObjectAnimator chame getters ou setters do código nativo com JNI. Os sistemas de animação mais recentes no Compose não exigem regras de manutenção como essa. É apenas um exemplo de estrutura de regra.

-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
   void set*(***);
   *** get*();
}

Registro de JNI

Essa regra de manutenção é empacotada dentro de androidx.graphics:graphics-path, usada para manter métodos nativos. Isso pode ser necessário se a biblioteca registrar manualmente métodos nativos com env->RegisterNatives().

-keepclasseswithmembers class androidx.graphics.path.** {
    native <methods>;
}