Personalizza le risorse da conservare

Quando attivi l'ottimizzazione delle app, il comportamento predefinito dell'ottimizzatore è diverso per le diverse versioni di R8.

  • Con il DSL aggiornato disponibile a partire da AGP 9.3 e versioni successive, la riduzione delle risorse è attivata per impostazione predefinita quando l'ottimizzazione è abilitata. Tieni presente che il DSL legacy, che richiede l'attivazione distinta dell'ottimizzazione del codice e delle risorse, è ancora supportato.
  • Per le versioni precedenti ad AGP 9.3, l'impostazione isShrinkResources = true indica all'ottimizzatore di rimuovere le risorse inutilizzate, il che contribuisce a ridurre le dimensioni dell'app. La riduzione delle risorse funziona solo in combinazione con la riduzione del codice, quindi se stai ottimizzando le risorse, imposta anche isMinifyEnabled = true.

AGP 9.3+ (Kotlin)

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

AGP 9.3+ (Groovy)

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

DSL legacy (Kotlin)

buildTypes {
    release {
        isMinifyEnabled = true
        isShrinkResources = true
        ...
    }
}

DSL precedente (Groovy)

buildTypes {
    release {
        minifyEnabled = true
        shrinkResources = true
        ...
    }
}

Se vuoi conservare o eliminare risorse specifiche, crea un file XML keep nelle risorse del progetto, ad esempio res/raw/my.package.keep.xml. Il file di conservazione contiene i seguenti componenti:

  • Tag <resources>: contiene tutti gli elementi delle risorse secondarie e gli attributi keep/discard.
  • Attributo tools:keep: accetta un elenco separato da virgole di nomi di risorse che identificano le risorse da conservare
  • Attributo tools:discard: accetta un elenco separato da virgole di nomi di risorse che identificano le risorse da eliminare

Utilizza l'asterisco come carattere jolly per fare riferimento a più risorse nella stessa cartella, ad esempio:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

Specificare le risorse da eliminare potrebbe sembrare superfluo quando potresti eliminarle, ma eliminare le risorse può essere utile quando si utilizzano varianti di build.

Scegliere come target varianti di build specifiche

Per rimuovere le risorse solo in alcune varianti di compilazione, inserisci tutte le risorse nella directory del progetto comune, quindi crea un file my.package.build.variant.keep.xml diverso per ogni variante di compilazione nella directory delle risorse della variante. Nel file keep, specifica manualmente le risorse da rimuovere quando una determinata risorsa sembra essere utilizzata nel codice (e quindi non rimossa dal riduttore), ma sai che in realtà non verrà utilizzata per la variante di compilazione specificata.

Rimuovere le risorse alternative inutilizzate

Lo strumento di ottimizzazione rimuove solo le risorse a cui non fa riferimento il codice dell'app, il che significa che non rimuove le risorse alternative per le diverse configurazioni del dispositivo.

Utilizza la proprietà resConfigs di Android Gradle nel file build.gradle del modulo della tua app per rimuovere i file di risorse alternativi che non sono necessari per la tua app.

Ad esempio, se utilizzi una libreria che include risorse linguistiche (come Google Play Services), la tua app include tutte le stringhe di lingua tradotte per i messaggi in queste librerie, indipendentemente dal fatto che il resto dell'app sia tradotto nelle stesse lingue o meno. Per conservare solo le lingue supportate ufficialmente dalla tua app, specifica queste lingue utilizzando la proprietà resConfigs. Vengono rimosse tutte le risorse per le lingue non specificate.

I seguenti snippet mostrano come limitare le risorse linguistiche solo all'inglese e al francese:

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

o

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

Quando pubblichi un'app utilizzando il formato Android App Bundle (AAB), per impostazione predefinita vengono scaricate solo le lingue configurate sul dispositivo di un utente quando l'utente installa l'app. Allo stesso modo, nel download sono incluse solo le risorse corrispondenti alla densità dello schermo del dispositivo e le librerie native corrispondenti all'ABI del dispositivo. Per saperne di più, consulta Riattivare o disattivare i tipi di APK di configurazione.

Per le app legacy rilasciate con APK (create prima di agosto 2021), puoi personalizzare le risorse di densità dello schermo o ABI da includere nell'APK creando più APK destinati a diverse configurazioni di dispositivi.

Evitare conflitti durante l'unione delle risorse

Per impostazione predefinita, il plug-in Android per Gradle (AGP) unisce le risorse con lo stesso nome, ad esempio le risorse drawable con lo stesso nome che si trovano in cartelle delle risorse diverse. Questo comportamento non è controllato dalla proprietà shrinkResources e non può essere disattivato perché è necessario per evitare errori quando più risorse hanno il nome a cui fa riferimento il codice.

L'unione delle risorse si verifica solo quando due o più file condividono nome, tipo e qualificatore identici. AGP seleziona il file che identifica come la scelta migliore tra i duplicati (in base a un ordine di priorità descritto di seguito) e passa solo quella risorsa ad AAPT per la distribuzione nell'artefatto di build finale.

AGP cerca risorse duplicate nelle seguenti posizioni:

  • Risorse principali, associate al set di risorse principale, generalmente situate in src/main/res/
  • Overlay delle varianti, dal tipo di compilazione e dalle versioni di build
  • Dipendenze del progetto della libreria

AGP unisce le risorse duplicate nel seguente ordine di priorità a cascata:

Dipendenze → Principale → Versione build → Tipo di compilazione

Ad esempio, se una risorsa duplicata viene visualizzata sia nelle risorse principali sia in una variante di build, Gradle seleziona la risorsa nella variante di build.

Se risorse identiche vengono visualizzate nello stesso set di risorse, Gradle non può unirle ed emette un errore di unione delle risorse. Ciò può accadere se definisci più set di origini nella proprietà sourceSet del file build.gradle del modulo, ad esempio se src/main/res/ e src/main/res2/ contengono risorse identiche.

Risolvere i problemi relativi alla riduzione delle risorse

Quando riduci le risorse, la finestra Build mostra un riepilogo delle risorse rimosse dall'app. (Fai clic su Attiva/disattiva visualizzazione sul lato sinistro della finestra per visualizzare l'output di testo dettagliato di Gradle.) Ad esempio:

:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

Gradle crea anche un file di diagnostica denominato resources.txt in <module-name>/build/outputs/mapping/release/ (la stessa cartella dei file di output di ProGuard). Il file include dettagli come quali risorse fanno riferimento ad altre risorse e quali risorse vengono utilizzate o rimosse.

Ad esempio, per scoprire perché @drawable/ic_plus_anim_016 è ancora presente nella tua app, apri il file resources.txt e cerca il nome del file. Potresti notare che viene fatto riferimento a un'altra risorsa:

16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016

Ora devi sapere perché @drawable/add_schedule_fab_icon_anim è raggiungibile; se cerchi verso l'alto, troverai la risorsa elencata sotto l'intestazione Le risorse raggiungibili dalla radice sono: in resources.txt.

Ciò significa che esiste un riferimento al codice add_schedule_fab_icon_anim, ovvero il relativo ID R.drawable è stato trovato nel codice raggiungibile.

A meno che non utilizzi il controllo rigoroso, gli ID risorsa possono essere contrassegnati come raggiungibili se sono presenti costanti stringa che sembrano poter essere utilizzate per costruire i nomi delle risorse caricate dinamicamente. In questo caso, se cerchi il nome della risorsa nell'output della build, potresti trovare un messaggio come questo:

10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
    used because its format-string matches string pool constant ic_plus_anim_%1$d.

Se visualizzi una di queste stringhe e hai la certezza che non venga utilizzata per caricare dinamicamente la risorsa specificata, utilizza l'attributo tools:discard nel file keep per comunicare al sistema di compilazione di rimuovere la risorsa.