Aggiungi regole di conservazione

Quando attivi l'ottimizzazione dell'app con le impostazioni predefinite, R8 esegue ottimizzazioni approfondite per massimizzare i vantaggi in termini di rendimento. R8 apporta modifiche sostanziali al codice, tra cui rinominazione, spostamento e rimozione di metodi e campi delle classi. Se ciò causa errori, devi specificare le parti del codice da non modificare scrivendo keep rules.

R8 potrebbe rimuovere o modificare in modo errato il codice nelle seguenti situazioni:

  • Riflessione: codice a cui si accede utilizzando la riflessione, ad esempio con Class.forName() o Method.invoke(). In genere, R8 non è in grado di stabilire a quali classi o metodi verrà eseguito l'accesso in questo modo.
  • Serializzazione: le classi o i campi necessari per la serializzazione e la deserializzazione potrebbero sembrare inutilizzati per R8 (questa è un'altra forma di riflessione).
  • Java Native Interface (JNI): metodi Java chiamati dal codice nativo. R8 non analizza il codice nativo per vedere cosa potrebbe richiamare in Java.

Questa pagina spiega come limitare l'entità delle ottimizzazioni di R8. Per scoprire come personalizzare le risorse da conservare, consulta Aggiungere regole di conservazione per le risorse.

Dove aggiungere le regole di conservazione

Devi aggiungere le regole a un file proguard-rules.pro situato nella directory principale del modulo (il file potrebbe essere già presente, ma se non lo è, crealo). Per applicare le regole nel file, devi dichiararlo nel file build.gradle.kts (o build.gradle) a livello di modulo, come mostrato nel codice seguente:

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'
            )
        }
    }
    // ...
}

Per impostazione predefinita, lo script di compilazione include anche il file proguard-android-optimize.txt. Questo file include regole necessarie per la maggior parte dei progetti Android, quindi dovresti mantenerlo nello script di compilazione.

Come scrivere le regole di conservazione

Durante la compilazione dell'app, R8 rileva il codice che deve essere mantenuto in un'app analizzando il grafo delle chiamate dell'app, che inizia dalle voci manifest (ad esempio le attività o i servizi) e viene tracciato in ogni chiamata di funzione dell'app e della libreria. In questo modo, R8 rimuove il codice a cui non viene fatto riferimento direttamente, il che può causare problemi se il codice eseguito non fa parte di questo grafo, ad esempio il codice invocato per riflessione. Scrivendo le tue regole di mantenimento, puoi indicare a R8 il codice che deve rimanere nell'app.

Per aggiungere una regola di conservazione, aggiungi una riga -keep nel file proguard-rules.pro.

Mantieni la sintassi della regola

Le regole Keep generalmente seguono questo formato:

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

Ad esempio, per preservare una classe specifica e tutti i relativi membri, utilizza quanto segue:

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

Per altri esempi, consulta la sezione degli esempi.

Ecco cosa fanno i componenti delle regole di mantenimento:

  • <KeepOption> ti consente di specificare quali aspetti di un corso conservare:

    Opzione Mantieni Descrizione

    -keep

    Mantieni il corso e i membri elencati in [{ OptionalMemberSpecification }].

    -keepclassmembers

    Consenti l'ottimizzazione del corso. Se il corso viene conservato, conserva i membri elencati in [{ OptionalMemberSpecification }].

    -keepnames

    Consenti la rimozione della classe e dei membri, ma non oscurare o modificare in altri modi.

    -keepclassmembernames

    Consenti la rimozione della classe e dei membri, ma non offuscare o modificare i membri in altri modi.

    -keepclasseswithmembers

    Nessuna rimozione o offuscamento dei gruppi se i membri corrispondono al pattern specificato.

    Ti consigliamo di utilizzare principalmente -keepclassmembers, poiché consente il maggior numero di ottimizzazioni, e poi -keepnames, se necessario. -keep non consente ottimizzazioni, quindi cerca di utilizzarlo con parsimonia.

  • [OptionalModifier],...] ti consente di elencare zero o più modificatori del linguaggio Java di un'aula, ad esempio public o final.

  • <ClassSpecification> consente di specificare a quale classe (o superclasse o interfaccia implementata) deve essere applicata la regola keep. Nel caso più semplice, si tratta di una classe completa.

  • [{ OptionalMemberSpecification }] ti consente di filtrare il comportamento di mantenimento solo per le classi e i metodi corrispondenti a determinati pattern. In genere, questo valore è consigliato nella maggior parte delle regole di conservazione per evitare di conservare più di quanto previsto.

Esempi di regole Keep

Ecco alcuni esempi di regole di conservazione ben progettate.

Costruisci sottoclasse

Questa regola di conservazione è pacchettizzata in androidx.room:room-runtime per mantenere instantiati per riflessione i costruttori del database.

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

Riflessione dal framework Android ObjectAnimator

Questa regola keep è pacchettizzata in androidx.vectordrawable:vectordrawable-animated per consentire a ObjectAnimator di chiamare getter o setter dal codice nativo con JNI. Tieni presente che i sistemi di animazione più recenti in Compose non richiedono regole keep come questa. Si tratta solo di un esempio di struttura della regola.

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

Registrazione JNI

Questa regola di mantenimento è pacchettizzata in androidx.graphics:graphics-path e viene utilizzata per mantenere i metodi nativi. Questo potrebbe essere necessario se la tua libreria registra manualmente i metodi nativi con env->RegisterNatives().

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