Scegli le librerie con cura

Per attivare l'ottimizzazione delle app, devi utilizzare librerie compatibili con l'ottimizzazione di Android. Se una libreria non è configurata per l'ottimizzazione per Android, ad esempio se utilizza la riflessione senza raggruppare le regole keep associate, potrebbe non essere adatta per un'app Android. Questa pagina spiega perché alcune librerie sono più adatte all'ottimizzazione delle app e fornisce suggerimenti generali per aiutarti a scegliere.

Preferisci la generazione di codice alla riflessione

In genere, devi scegliere librerie che utilizzano la generazione di codice (codegen) anziché la riflessione. Con codegen, l'ottimizzatore può determinare più facilmente quale codice viene effettivamente utilizzato in fase di esecuzione e quale può essere rimosso. Può essere difficile capire se una libreria utilizza la compilazione automatica o la riflessione, ma ci sono alcuni indicatori. Consulta i suggerimenti per ricevere assistenza.

Per ulteriori informazioni sul confronto tra codegen e la riflessione, consulta Ottimizzazione per gli autori delle librerie.

Suggerimenti generali per la scelta delle librerie

Segui questi suggerimenti per assicurarti che le tue librerie siano compatibili con l'ottimizzazione delle app.

Verificare la presenza di problemi di ottimizzazione

Quando valuti una nuova libreria, controlla il tracker dei problemi e le discussioni online della libreria per verificare se ci sono problemi relativi alla minimizzazione o alla configurazione dell'ottimizzazione dell'app. Se sono presenti, dovresti provare a cercare alternative a quella raccolta. Tieni presente quanto segue:

  • Le librerie AndroidX e librerie come Hilt funzionano bene con l'ottimizzazione dell'app perché utilizzano codegen anziché la riflessione. Quando lo fanno, forniscono regole di conservazione minime per mantenere solo il codice necessario.
  • Le librerie di serializzazione utilizzano spesso la riflessione per evitare il codice boilerplate quando si eseguono l'inizializzazione o la serializzazione degli oggetti. Anziché gli approcci basati sulla riflessione (come Gson per JSON), cerca librerie che utilizzino la compilazione automatica per evitare questi problemi, ad esempio utilizzando Kotlin Serialization.
  • Se possibile, evita le librerie che includono regole keep per l'intero pacchetto. Le regole keep a livello di pacchetto possono essere utili per risolvere gli errori, ma le regole keep generiche devono essere perfezionate per mantenere solo il codice necessario. Per maggiori informazioni, consulta Adottare le ottimizzazioni in modo incrementale.

Attivare l'ottimizzazione dopo aver aggiunto una nuova libreria

Quando aggiungi una nuova libreria, attiva l'ottimizzazione in un secondo momento e controlla se ci sono errori. Se sono presenti errori, cerca alternative alla libreria o scrivi regole keep. Se una libreria non è compatibile con l'ottimizzazione, segnala un bug per la libreria in questione.

Le regole sono cumulative

Tieni presente che le regole di conservazione sono cumulative. Ciò significa che alcune regole incluse in una dipendenza della libreria non possono essere rimosse e potrebbero influire sulla compilazione di altre parti dell'app. Ad esempio, se una libreria include una regola per disattivare le ottimizzazioni del codice, questa regola disattiva le ottimizzazioni per l'intero progetto.

Verificare l'utilizzo della riflessione (avanzato)

Potresti essere in grado di capire se una libreria utilizza la riflessione dall'ispezione del codice. Se la libreria utilizza la riflessione, verifica che fornisca le regole di conservazione associate. Una biblioteca probabilmente utilizza la riflessione se esegue le seguenti operazioni:

  • Utilizza classi o metodi dei pacchetti kotlin.reflect o java.lang.reflect
  • Utilizza le funzioni Class.forName o classLoader.getClass
  • Legge le annotazioni in fase di esecuzione, ad esempio se memorizza un valore di annotazione utilizzando val value = myClass.getAnnotation() o val value = myMethod.getAnnotation() e poi esegue un'azione con value
  • Chiama i metodi utilizzando il nome del metodo come stringa, ad esempio:

    // Calls the private `processData` API with reflection
    myObject.javaClass.getMethod("processData", DataType::class.java)
    ?.invoke(myObject, data)
    

Filtrare le regole di conservazione errate (avanzate)

Evita le librerie con regole keep che mantengono il codice che dovrebbe essere rimosso. Tuttavia, se devi utilizzarle, puoi escludere le regole come mostrato nel seguente codice:

// If you're using AGP 8.4 and higher
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreFrom("com.somelibrary:somelibrary")
        }
    }
}

// If you're using AGP 7.3-8.3
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreExternalDependencies("com.somelibrary:somelibrary")
        }
    }
}

Case study: perché Gson si interrompe con le ottimizzazioni

Gson è una libreria di serializzazione che spesso causa problemi di ottimizzazione dell'app perché utilizza molto la riflessione. Il seguente snippet di codice mostra come viene tipicamente utilizzato Gson, il che può causare facilmente arresti anomali in fase di esecuzione. Tieni presente che quando utilizzi Gson per ottenere un elenco di oggetti User, non chiami il costruttore né passi una factory alla funzione fromJson(). La costruzione o l'utilizzo di classi definite dall'app senza uno dei seguenti elementi è un segno che una libreria potrebbe utilizzare la riflessione aperta:

  • Classe di app che implementa una libreria o un'interfaccia o una classe standard
  • Plug-in di generazione di codice come KSP
class User(val name: String)
class UserList(val users: List<User>)

// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()

Quando R8 analizza questo codice e non vede UserList o User inizializzati da nessuna parte, può rinominare i campi o rimuovere i costruttori che non sembrano essere utilizzati, causando l'arresto anomalo dell'app. Se utilizzi altre librerie in modi simili, devi verificare che non interferiscano con l'ottimizzazione dell'app e, in caso contrario, evitarle.

Tieni presente che sia Room sia Hilt generano tipi definiti dall'app, ma utilizzano codegen per evitare la necessità di riflessione.