La guerre contre les octets de votre application Android

Cover image

Votre application est sur les stores depuis quelques jours et, si vous avez bien travaillé, les 5 étoiles défilent dans les avis.

Mais ce matin, vous découvrez que Michel n’a donné qu’une seule étoile :

J’ai un Motorola G de 8Go, votre application prend trop de place, je ne veux pas la télécharger

Michel n’est surement pas le seul dans ce cas, mais le fait qu’il vous ai mis un mauvais avis vous motive à déclarer la guerre aux octets.

Épisode 1 : L‘éclaireur

On ne délivre pas sa première bataille sans un plan efficace. Pour connaitre votre première cible, vous avez besoin d’abord besoin d’analyser la situation.

Sur Android Studio, vous pouvez analyser la taille de vos APKs dans le menu build > Analyse APK…

Menu permettant d’accéder à l’analyse d’APK

Analysons donc cet APK de 37.4 MB

Cette première analyse révèle que prêt de la moitié de votre APK est occupée par des librairies précompilées au format so dont vous ne connaissiez même pas l’existence.

Elles se permettent en plus d’être dupliquées sur 6 architecture différentes : x86_64, arm64-v8a, x86, armabi-v7a, mips et armeabi

Vous repérez rapidement vos trois premières cibles : realm, opencv et card.io.

Realm est la seule librairie que vous devrez épargner étant donné que vous l’utilisez dans votre application.

Épisode 2 : La cible prioritaire

Quelques recherches sur Internet nous amène à la conclusion qu’opencv est inclus dans card.io.

Card.io est une librairie qui permet de scanner des cartes de crédits avec l’appareil photo du téléphone afin d’en récupérer les informations. Cette librairie est embarqué dans une des librairies de paiement que vous utilisez (ici paypal).

Le soucis ici est que vous n’utilisez pas cette fonctionnalité de scan.

On va donc pouvoir retirer cette dépendance.

implementation("com.paypal.sdk:paypal-android-sdk:$PAYPAL_VERSION") {
    exclude group: 'io.card'
}

Voyons voir le résultat de cette première attaque.

Félicitations, cette première bataille est un succès. Nous venons de réduire la taille de l’APK de 11.9 MB l’amenant ainsi à 25.5 MB (32% de réduction)

Episode 3 : Affaiblir l’adversaire

La librairie realm est précompilée pour 5 architectures. Est-ce que toutes ces architectures sont vraiment utilisées ?

Cet article de Brijesh Masrani va nous éclairer. Résumons le avec quelques points clés.

Seules trois architectures sont utilisées. Et vous pouvez réduire ce chiffre à deux en faisant une concession sur les performances des appareils tournant sous arm64-v8a :

Vous pouvez donc filtrer l’inclusion de ces librairies en ajoutant un filtre à votre fichier gradle :

android {
    defaultConfig {
        applicationId "com.android.abi.myapplication"
        minSdkVersion 17
        targetSdkVersion 25

        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }
}

Le résultat nous permet de constater que nous avons encore gagné 3.1MB.

La réduction de l’APK est maintenant de 15 MB l’amenant ainsi à 22.4 MB (40% de réduction) Il faut noter qu’à partir de la version 3.2 du plugin gradle Android, les architectures armabi, mips et mips64 ne seront plus inclues par défaut et qu’il faudra donc, au contraire, expliciter si vous souhaitez des builds compatibles.

Episode 4 : La police arrive en support

Le répertoire assets de ce package abrite, entre autre, des polices au format ttf mais, bizarrement, la plupart d’entre elles ne sont ici pas utilisées.

Si votre application est compatible avec l’API 14 et plus, vous pouvez utiliser des polices téléchargeables grâce à la librairie de support.

On va donc ici pouvoir retirer 2.5 MB de fichiers ttf de notre APK.

La réduction de l’APK est maintenant de 17.5 MB l’amenant ainsi à 19.9 MB (47% de réduction)

Episode 5 : Le régime militaire du format webp

Le répertoire res contient les ressources de l’application, et une grande partie de l’espace occupée de notre nouvel APK concerne maintenant les images de notre application.

Nos images les plus lourdes vont devoir subir le régime du format webp.

Le format webp peut être vraiment très efficace et nous amener à diviser par plus de 10 le poids de certaines de nos images.

Voyons ce qu’a donné cette compression :

La réduction de l’APK est maintenant de 20.3 MB l’amenant ainsi à 17.1 MB (54% de réduction)

Episode 6 : Diviser pour mieux régner

Le splitting d’APK va nous permettre de générer des packages sur mesure en fonction des directives que nous allons spécifier à gradle.

android {
    ...
    splits {
        // Configures multiple APKs based on screen density.
        density {

            // Configures multiple APKs based on screen density.
            enable true

            // Specifies a list of screen densities Gradle should not create multiple APKs for.
            exclude "ldpi"
        }
        // Configures multiple APKs based on ABI.
        abi {

            // Enables building multiple APKs per ABI.
            enable true

            // Resets the list of ABIs that Gradle should create APKs for to none.
            reset()

            // Specifies a list of ABIs that Gradle should create APKs for.
            include "x86", "armeabi-v7a"

            // Specifies that we do not want to also generate a universal APK that includes all ABIs.
            universalApk false
        }
    }
}

Lisez attentivement la documentation avant de mettre en place cette technique. En effet, chaque apk devra disposer de son propre versionCode. Le Motorola G de Michel dispose de l’architecture armeabi-v7a et d’une densité de pixel xhdpi. Il téléchargera donc l’apk spécifique à cette configuration : superapp-production-xhdpiArmeabi-v7a.apk

La réduction de l’APK est maintenant de 28.8 MB l’amenant ainsi à 8.6 MB (77% de réduction).

Épilogue : Michel signe l’armistice

Notre ami Michel est très heureux de pouvoir télécharger un APK qui fait moins du quart de l’original. D’autant plus que nous lui avons aussi permis de l’installer sur la carte SD de son téléphone.