Informazioni sulle regole di conservazione

Quando attivi l'ottimizzazione delle app con le impostazioni predefinite, R8 esegue ottimizzazioni estese per massimizzare i vantaggi in termini di prestazioni. R8 apporta modifiche sostanziali al codice, tra cui la ridenominazione, lo spostamento e la rimozione di classi, campi e metodi. Se noti che queste modifiche causano errori, devi specificare quali parti del codice R8 non deve modificare dichiarandole nelle regole keep.

Scenari comuni che richiedono regole di conservazione

R8 identifica e conserva tutte le chiamate dirette nel codice. Tuttavia, R8 non può vedere gli utilizzi indiretti del codice, il che può causare la rimozione del codice necessario per l'app, provocando arresti anomali. Utilizza le regole di conservazione per indicare a R8 di conservare questo codice utilizzato indirettamente. Di seguito sono riportate alcune situazioni comuni in cui è probabile che tu debba utilizzare le regole di conservazione:

  • Codice a cui si accede tramite reflection: R8 non è in grado di identificare quando si accede a classi, campi o metodi tramite reflection. Ad esempio, R8 non può identificare un metodo cercato al volo in base al nome utilizzando Class.getDeclaredMethod() o un'annotazione recuperata con Class.getAnnotation(). In questi casi, R8 potrebbe rinominare questi metodi e annotazioni o rimuoverli del tutto, generando un errore ClassNotFoundException o NoSuchMethodException in fase di runtime.
  • Codice chiamato da Java Native Interface (JNI): quando il codice nativo (C o C++) chiama un metodo Java o Kotlin oppure il codice Java o Kotlin chiama il codice C++ con JNI, la chiamata si basa su una ricerca di stringhe dinamiche del nome del metodo. R8 non può vedere la chiamata al metodo dinamico basato su stringhe, pertanto le sue ottimizzazioni potrebbero interrompere il codice.

Questo non è un elenco esaustivo di scenari che richiedono regole di conservazione, ma questi scenari coprono la maggior parte dei casi in cui potresti averne bisogno.

Se il tuo codice utilizza la riflessione o viene chiamato da JNI, puoi annotarlo con le annotazioni Jetpack Keep anziché scrivere manualmente le regole di conservazione. Il suo plug-in Gradle genera le regole di conservazione dalle annotazioni in fase di build.

Scopri in che modo le regole di conservazione influiscono sull'ottimizzazione

R8 è un ottimizzatore dell'intero programma che analizza il codice dell'app per rimuovere il codice inutilizzato, i metodi incorporati, unire le classi e offuscare gli identificatori. Tuttavia, R8 può eseguire l'ottimizzazione solo all'interno della configurazione che definisci.

Le regole di conservazione rappresentano un'istruzione esplicita per limitare l'ottimizzazione. Ogni regola keep dichiarata limita la capacità di R8 di trasformare quella parte del codebase. Il valore di una regola di conservazione ben progettata risiede nella sua specificità:

  • Le regole di conservazione ristrette consentono la massima ottimizzazione: scegliendo come target solo i punti di accesso esatti a cui si accede in modo dinamico (ad esempio un costruttore riflessivo o un campo serializzato), consenti a R8 di ottimizzare il resto del codice.

  • Le regole di conservazione ampie impediscono l'ottimizzazione: la dichiarazione di regole a livello di pacchetto o di caratteri jolly ampi impedisce a R8 di ottimizzare intere classi e tutti i relativi membri. R8 non può rimuovere, incorporare, unire o offuscare il codice.

Regole di conservazione eccessivamente ampie portano direttamente a file binari DEX gonfi, a un aumento del footprint della memoria dell'app, a tempi di avvio più lenti (TTID e TTFD) e a percentuali di ANR più elevate. Il tuo obiettivo non deve essere quello di mantenere le classi "per ogni evenienza ", ma di definire il contratto minimo richiesto per l'esecuzione dinamica.

Per trovare regole di conservazione ampie o non necessarie, incluse quelle di librerie di terze parti, utilizza R8 Configuration Analyzer. Riporta i punteggi di riduzione, ottimizzazione e offuscamento che mostrano la quantità di codice che R8 può ottimizzare.

Come aggiungere regole di conservazione alla tua app

La configurazione delle regole di conservazione dipende dalla versione di AGP che utilizzi.

Le app più grandi in genere hanno il codice in più moduli di libreria. In questi casi, spesso è meglio inserire le regole di conservazione insieme al codice a cui si applicano all'interno del modulo della libreria specifico. La differenza fondamentale nel mantenere le regole di conservazione per le librerie risiede nel modo in cui dichiari queste regole all'interno del file build.gradle.kts (o build.gradle) del modulo della libreria. Per saperne di più, consulta Ottimizzazione per gli autori di librerie.

Per AGP versione 9.3 e successive

Aggiungi le regole a un file con il suffisso .keep nella directory src/<variant>/keepRules. Ad esempio src/main/keepRules/custom-rules.keep. Tieni presente che l'utilizzo del DSL aggiornato per AGP 9.3 e versioni successive attiva l'ottimizzazione del codice e delle risorse e non richiede di definire esplicitamente il file delle regole di conservazione predefinito di Android (proguard-android-optimize.txt), perché è incluso per impostazione predefinita, a meno che non venga omesso esplicitamente.

Kotlin

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
            }
        }
    }
}

Alla moda

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
            }
        }
    }
}

Ometti le regole di conservazione predefinite della piattaforma Android (avanzato)

AGP fornisce un insieme di regole predefinite della piattaforma Android. Per omettere queste regole dalla configurazione del progetto e gestire autonomamente tutte le regole di conservazione, imposta optimization.keepRules.includeDefault su false.

Kotlin

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
                keepRules {
                    includeDefault = false // The file with optimization
                    // rules for the Android platform is included by
                    // default. To omit this file, set this option to false.
                }
            }
        }
    }
}

Alla moda

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
                keepRules {
                    includeDefault = false // The file with optimization
                    // rules for the Android platform is included by
                    // default. To omit this file, set this option to false.
                }
            }
        }
    }
}

DSL legacy per versioni di AGP precedenti alla 9.3

Aggiungi le regole a un file proguard-rules.pro che si trova nella directory root del modulo dell'app. Il file potrebbe essere già presente, ma se non lo è, crealo. Per applicare le regole nel file, devi dichiarare il file nel file build.gradle.kts (o build.gradle) a livello di modulo.

Per impostazione predefinita, il file di build include anche il file proguard-android-optimize.txt. Questo file include le regole necessarie per la maggior parte dei progetti Android, quindi devi lasciarlo nel file di build. Questo file si basa sul file proguard-common.txt e condivide i contenuti con quest'ultimo.

DSL legacy (Kotlin)

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

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

DSL legacy (Groovy)

android {
    buildTypes {
        release {
            minifyEnabled = true
            shrinkResources = true

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

Aggiungi una regola di conservazione

Quando aggiungi regole di conservazione, puoi includere opzioni globali e definire le tue regole di conservazione.

  • Opzioni globali: le opzioni globali sono istruzioni generali che influiscono sul modo in cui R8 opera sull'intera codebase. Per saperne di più, consulta Opzioni globali.

  • Regole Keep: le regole Keep devono essere progettate con attenzione per garantire il giusto equilibrio tra la massimizzazione dell'ottimizzazione del codice e la prevenzione di interruzioni involontarie dell'app. Per scoprire come scrivere regole Keep, consulta Aggiungi regole Keep.

Regole di conservazione per gli autori delle librerie

Dopo aver appreso le opzioni globali e la sintassi per le regole keep, consulta Ottimizzazione per gli autori di librerie per ulteriori dettagli.