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()
oMethod.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 esempiopublic
ofinal
.<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>;
}