Ridurre le dimensioni dell'app

Gli utenti spesso evitano di scaricare app che sembrano troppo grandi, soprattutto nei mercati emergenti, dove i dispositivi si connettono a reti 2G e 3G instabili o funzionano con piani con limiti di dati. Questa pagina descrive come ridurre le dimensioni del download della tua app, in modo che un maggior numero di utenti possa scaricarla.

Caricare l'app con Android App Bundle

Carica la tua app come Android App Bundle per ridurre immediatamente le dimensioni dell'app quando la pubblichi su Google Play. Android App Bundle è un formato di caricamento che include tutto il codice e le risorse compilati della tua app, ma rimanda la generazione e la firma dell'APK a Google Play.

Il modello di pubblicazione delle app di Google Play utilizza poi l'app bundle per generare e pubblicare APK ottimizzati per la configurazione del dispositivo di ogni utente, in modo che scarichi solo il codice e le risorse necessari per eseguire l'app. Non devi creare, firmare e gestire più APK per supportare dispositivi diversi e gli utenti ottengono download più piccoli e ottimizzati.

Google Play applica una limitazione delle dimensioni di download compresso di 200 MB per le app pubblicate con app bundle. È possibile utilizzare dimensioni maggiori con Play Feature Delivery e Play Asset Delivery, ma l'aumento delle dimensioni dell'app può influire negativamente sulla riuscita dell'installazione e aumentare le disinstallazioni, pertanto ti consigliamo di applicare le linee guida descritte in questa pagina per ridurre il più possibile le dimensioni di download dell'app.

Comprendere la struttura dell'APK

Prima di ridurre le dimensioni dell'app, è utile comprendere la struttura dell'APK di un'app. Un file APK è costituito da un archivio ZIP che contiene tutti i file che compongono l'app. Questi file includono file di classe Java, file di risorse e un file contenente le risorse compilate.

Un APK contiene le seguenti directory:

  • META-INF/: contiene i file di firma CERT.SF e CERT.RSA, nonché il file manifest MANIFEST.MF.
  • assets/: contiene gli asset dell'app, che l'app può recuperare utilizzando un oggetto AssetManager.
  • res/: contiene risorse che non sono compilate in resources.arsc.
  • lib/: contiene il codice compilato specifico del livello software di un processore. Questa directory contiene una sottodirectory per ogni tipo di piattaforma, ad esempio armeabi, armeabi-v7a, arm64-v8a, x86, x86_64 e mips.

Un APK contiene anche i seguenti file. Solo AndroidManifest.xml è obbligatorio:

  • resources.arsc: contiene le risorse compilate. Questo file contiene i contenuti XML di tutte le configurazioni della cartella res/values/. Lo strumento di creazione del pacchetto estrae questi contenuti XML, li compila in formato binario e li archivia. Questi contenuti includono stringhe e stili di lingua, nonché percorsi a contenuti non inclusi direttamente nel file resources.arsc, come file di layout e immagini.
  • classes.dex: contiene le classi compilate nel formato di file DEX compreso dalla macchina virtuale Dalvik o ART.
  • AndroidManifest.xml: contiene il file manifest Android principale. Questo file elenca il nome, la versione, i diritti di accesso e i file di libreria a cui fa riferimento l'app. Il file utilizza il formato XML binario di Android.

Riduci il numero e le dimensioni delle risorse

Le dimensioni dell'APK influiscono sulla velocità di caricamento dell'app, sulla quantità di memoria utilizzata e sul consumo di energia. Puoi ridurre le dimensioni dell'APK diminuendo il numero e le dimensioni delle risorse che contiene. In particolare, puoi rimuovere le risorse che la tua app non utilizza più e puoi utilizzare oggetti Drawable scalabili al posto dei file immagine. Questa sezione illustra questi metodi e altri modi per ridurre le risorse nella tua app e diminuire le dimensioni complessive dell'APK.

Rimuovere le risorse inutilizzate

Lo strumento lint, un analizzatore di codice statico incluso in Android Studio, rileva le risorse nella cartella res/ a cui il tuo codice non fa riferimento. Quando lo strumento lint rileva una risorsa potenzialmente inutilizzata nel tuo progetto, stampa un messaggio come il seguente esempio:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
    to be unused [UnusedResources]

Le librerie che aggiungi al codice potrebbero includere risorse inutilizzate. Gradle può rimuovere automaticamente le risorse per tuo conto se attivi shrinkResources nel file build.gradle.kts della tua app.

Kotlin

android {
    // Other settings.

    buildTypes {
        getByName("release") {
            minifyEnabled = true
            shrinkResources = true
            proguardFiles(getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro")
        }
    }
}

Groovy

android {
    // Other settings.

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Per utilizzare shrinkResources, attiva la riduzione del codice. Durante la procedura di build, R8 rimuove innanzitutto il codice inutilizzato. Poi, il plug-in Android per Gradle rimuove le risorse non utilizzate.

Per ulteriori informazioni sulla riduzione del codice e delle risorse e su altri modi in cui Android Studio riduce le dimensioni degli APK, consulta Ridurre, offuscare e ottimizzare l'app.

Nel plug-in Android per Gradle 7.0 e versioni successive, puoi dichiarare le configurazioni supportate dalla tua app. Gradle trasmette queste informazioni al sistema di build utilizzando il resourceConfigurations flavor e l'opzione defaultConfig. Il sistema di compilazione impedisce quindi la visualizzazione delle risorse di altre configurazioni non supportate nell'APK, riducendone le dimensioni. Per ulteriori informazioni su questa funzionalità, consulta Rimuovere le risorse alternative inutilizzate.

Ridurre al minimo l'utilizzo delle risorse delle librerie

Quando sviluppi un'app per Android, di solito utilizzi librerie esterne per migliorare l'usabilità e la versatilità dell'app. Ad esempio, puoi fare riferimento ad AndroidX per migliorare l'esperienza utente sui dispositivi precedenti oppure puoi utilizzare Google Play Services per recuperare le traduzioni automatiche del testo all'interno dell'app.

Se una libreria è progettata per un server o un computer, può includere molti oggetti e metodi che la tua app non richiede. Per includere solo le parti della libreria di cui la tua app ha bisogno, puoi modificare i file della libreria se la licenza ti consente di farlo. Puoi anche utilizzare una libreria alternativa ottimizzata per il mobile per aggiungere funzionalità specifiche alla tua app.

Decodifica delle immagini animate native

In Android 12 (livello API 31), l'API NDK ImageDecoder viene estesa per decodificare tutti i frame e i dati di temporizzazione delle immagini che utilizzano i formati di file GIF animata e WebP animato.

Utilizza ImageDecoder anziché librerie di terze parti per ridurre ulteriormente le dimensioni dell'APK e usufruire di futuri aggiornamenti relativi a sicurezza e prestazioni.

Per maggiori dettagli sull'API ImageDecoder, consulta API reference e l'esempio su GitHub.

Supporta solo densità specifiche

Android supporta diverse densità dello schermo, ad esempio:

  • ldpi
  • mdpi
  • tvdpi
  • hdpi
  • xhdpi
  • xxhdpi
  • xxxhdpi

Sebbene Android supporti le densità precedenti, non è necessario esportare le risorse rasterizzate in ogni densità.

Se sai che solo una piccola percentuale dei tuoi utenti ha dispositivi con densità specifiche, valuta se devi raggruppare queste densità nella tua app. Se non includi risorse per una densità dello schermo specifica, Android ridimensiona automaticamente le risorse esistenti originariamente progettate per altre densità dello schermo.

Se la tua app ha bisogno solo di immagini scalate, puoi risparmiare ancora più spazio con una sola variante di un'immagine in drawable-nodpi/. Ti consigliamo di includere almeno una variante dell'immagine xxhdpi nella tua app.

Per ulteriori informazioni sulle densità schermo, vedi Dimensioni e densità dello schermo.

Utilizzare oggetti disegnabili

Alcune immagini non richiedono una risorsa immagine statica. Il framework può disegnare dinamicamente l'immagine in fase di runtime. Gli oggetti Drawable o <shape> in XML possono occupare una quantità minima di spazio nell'APK. Inoltre, gli oggetti XML Drawable producono immagini monocromatiche conformi alle linee guida di Material Design.

Riutilizzare le risorse

Puoi includere una risorsa separata per le variazioni di un'immagine, ad esempio versioni colorate, ombreggiate o ruotate della stessa immagine. Tuttavia, ti consigliamo di riutilizzare lo stesso insieme di risorse e di personalizzarle in base alle esigenze in fase di runtime.

Android fornisce diverse utilità per modificare il colore di una risorsa, utilizzando gli attributi android:tint e tintMode.

Puoi anche omettere le risorse che sono solo un equivalente ruotato di un'altra risorsa. Il seguente snippet di codice fornisce un esempio di trasformazione di un "Mi piace" in un "Non mi piace" ruotando l'immagine di 180 gradi attorno al centro:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_thumb_up"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="180" />

Rendering dal codice

Puoi anche ridurre le dimensioni dell'APK eseguendo il rendering procedurale delle immagini. Il rendering procedurale libera spazio perché non memorizzi più un file immagine nell'APK.

Comprimere i file PNG

Lo strumento aapt può ottimizzare le risorse immagine inserite in res/drawable/ con compressione lossless durante il processo di compilazione. Ad esempio, lo strumento aapt può convertire un PNG a colori reali che non richiede più di 256 colori in un PNG a 8 bit con una tavolozza di colori. In questo modo, l'immagine avrà la stessa qualità, ma occuperà meno spazio di memoria.

aapt presenta le seguenti limitazioni:

  • Lo strumento aapt non riduce le dimensioni dei file PNG contenuti nella cartella asset/.
  • I file immagine devono utilizzare 256 colori o meno per consentire allo strumento aapt di ottimizzarli.
  • Lo strumento aapt potrebbe gonfiare i file PNG già compressi. Per evitare questo problema, puoi utilizzare il flag isCrunchPngs per disattivare questa procedura per i file PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Groovy

        buildTypes.all { isCrunchPngs = false }
        

Comprimere i file PNG e JPEG

Puoi ridurre le dimensioni dei file PNG senza perdere la qualità dell'immagine utilizzando strumenti come pngcrush, pngquant o zopflipng. Tutti questi strumenti possono ridurre le dimensioni dei file PNG mantenendo la qualità percettiva dell'immagine.

Lo strumento pngcrush è particolarmente efficace. Questo strumento esamina i filtri PNG e i parametri zlib (Deflate), utilizzando ogni combinazione di filtri e parametri per comprimere l'immagine. Quindi, sceglie la configurazione che produce l'output compresso più piccolo.

Per comprimere i file JPEG, puoi utilizzare strumenti come packJPG e guetzli.

Utilizzare il formato di file WebP

Anziché utilizzare file PNG o JPEG, puoi utilizzare anche il formato WebP per le tue immagini. Il formato WebP offre compressione con perdita e trasparenza, come JPG e PNG, e può fornire una compressione migliore rispetto a JPEG o PNG.

Puoi convertire le immagini BMP, JPG, PNG o GIF statiche esistenti nel formato WebP utilizzando Android Studio. Per ulteriori informazioni, vedi Creare immagini WebP.

Utilizzare grafica vettoriale

Puoi utilizzare la grafica vettoriale per creare icone indipendenti dalla risoluzione e altri contenuti multimediali scalabili. Puoi utilizzare queste immagini per ridurre notevolmente l'ingombro dell'APK. Le immagini vettoriali sono rappresentate in Android come oggetti VectorDrawable. Con un oggetto VectorDrawable, un file di 100 byte può generare un'immagine nitida delle dimensioni dello schermo.

Tuttavia, il sistema impiega molto più tempo per eseguire il rendering di ogni oggetto VectorDrawable e le immagini più grandi impiegano ancora più tempo per essere visualizzate sullo schermo. Pertanto, valuta la possibilità di utilizzare queste immagini vettoriali solo quando visualizzi immagini di piccole dimensioni.

Per ulteriori informazioni sull'utilizzo degli oggetti VectorDrawable, consulta Drawables.

Utilizzare la grafica vettoriale per le immagini animate

Non utilizzare AnimationDrawable per creare animazioni fotogramma per fotogramma, perché in questo modo è necessario includere un file bitmap separato per ogni fotogramma dell'animazione, il che aumenta drasticamente le dimensioni dell'APK.

Utilizza invece AnimatedVectorDrawableCompat per creare risorse grafiche vettoriali animate.

Ridurre il codice nativo e Java

Puoi utilizzare i seguenti metodi per ridurre le dimensioni del codebase Java e nativo nella tua app.

Rimuovere il codice generato non necessario

Assicurati di comprendere l'impronta di qualsiasi codice generato automaticamente. Ad esempio, molti strumenti di protocol buffer generano un numero eccessivo di metodi e classi, che possono raddoppiare o triplicare le dimensioni dell'app.

Evitare le enumerazioni

Una singola enumerazione può aggiungere circa 1-1,4 KB al file classes.dex della tua app. Queste aggiunte possono accumularsi rapidamente per sistemi complessi o librerie condivise. Se possibile, valuta la possibilità di utilizzare l'annotazione @IntDef e la riduzione del codice per rimuovere le enumerazioni e convertirle in numeri interi. Questa conversione del tipo conserva tutti i vantaggi della sicurezza dei tipi degli enum.

Ridurre le dimensioni dei binari nativi

Se la tua app utilizza codice nativo e l'NDK Android, puoi anche ridurre le dimensioni della versione di rilascio ottimizzando il codice. Due tecniche utili sono la rimozione dei simboli di debug e la mancata estrazione delle librerie native.

Rimuovere i simboli di debug

L'utilizzo dei simboli di debug è utile se la tua app è in fase di sviluppo e richiede ancora il debug. Utilizza lo strumento arm-eabi-strip fornito in Android NDK per rimuovere i simboli di debug non necessari dalle librerie native. Dopodiché, puoi compilare la build della release.

Evitare l'estrazione delle librerie native

Quando crei la versione di rilascio della tua app, inserisci i file .so non compressi nell'APK impostando useLegacyPackaging su false nel file build.gradle.kts dell'app. La disattivazione di questo flag impedisce a PackageManager di copiare i file .so dall'APK al file system durante l'installazione. Questo metodo rende più piccoli gli aggiornamenti della tua app.

Mantenere più APK lean

Il tuo APK potrebbe contenere contenuti che gli utenti scaricano ma non utilizzano mai, come risorse linguistiche aggiuntive o per densità dello schermo. Per garantire un download minimo per i tuoi utenti, carica la tua app su Google Play utilizzando Android App Bundle. Il caricamento degli app bundle consente a Google Play di generare e pubblicare APK ottimizzati per la configurazione del dispositivo di ogni utente, in modo che scarichino solo il codice e le risorse necessari per eseguire la tua app. Non devi creare, firmare e gestire più APK per supportare dispositivi diversi e gli utenti ottengono download più piccoli e ottimizzati.

Se non pubblichi la tua app su Google Play, puoi segmentarla in diversi APK, differenziati in base a fattori quali le dimensioni dello schermo o il supporto delle texture della GPU.

Quando un utente scarica la tua app, il suo dispositivo riceve l'APK corretto in base alle funzionalità e alle impostazioni del dispositivo. In questo modo, i dispositivi non ricevono asset per funzionalità che non hanno. Ad esempio, se un utente ha un dispositivo hdpi, non ha bisogno di risorse xxxhdpi che potresti includere per i dispositivi con display ad alta densità.

Per ulteriori informazioni, vedi Creare più APK e Supporto di più APK.