Android
Multidex et la limite de méthode Dex
Recherche…
Introduction
DEX désigne les fichiers de code-octet exécutables de l'application Android (APK) sous la forme de fichiers Dalvik Executable (DEX), qui contiennent le code compilé utilisé pour exécuter votre application.
La spécification Dalvik Executable limite le nombre total de méthodes pouvant être référencées dans un seul fichier DEX à 65 536 (64 Ko), y compris les méthodes d'infrastructure Android, les méthodes de bibliothèque et les méthodes de votre propre code.
Pour surmonter cette limite, vous devez configurer le processus de génération de votre application afin de générer plusieurs fichiers DEX, appelés Multidex.
Remarques
Qu'est ce que le dex?
Dex est le nom du format de fichier et du codage auquel le code Java Android est compilé. Les premières versions d'Android chargeraient et exécuteraient des binaires dex
directement dans une machine virtuelle nommée Dalvik. Les versions plus récentes d'Android utilisent Android Runtime (ART), qui traite les fichiers dex
comme une représentation intermédiaire et effectue de nouvelles compilations avant d'exécuter l'application.
Dex est un format de fichier très ancien, en termes de durée de vie des smartphones, conçu pour les périphériques dont la mémoire principale était mesurée en dizaines de mégaoctets. Les limites de conception de ces jours sont restées avec nous à ce jour.
Le problème:
Le format de fichier dex
encode une limite au nombre de méthodes pouvant être référencées dans un seul fichier binaire. Étant donné que la partie du format de fichier qui stocke le nombre de références comporte deux octets, le nombre maximal de références de méthode est 0xFFFF
ou 65535. Si une application contient plus de ce nombre de références de méthode, la compilation échouera.
Que faire à ce sujet:
Google a fourni un moyen de contourner ce problème, appelé Multidex. Il comporte des composants à la compilation et à l'exécution. Comme son nom l'indique, au moment de la compilation, il divisera le code entre un ou plusieurs fichiers dex
. Lors de l'exécution, le ClassLoader
par défaut ClassLoader
à rechercher les classes à partir de ces fichiers.
Cette approche fonctionne bien sur les nouveaux périphériques, mais présente des inconvénients importants. Il peut augmenter le temps de démarrage de l' application de façon spectaculaire, et sur les appareils plus anciens peuvent causer Application Not Responding
des échecs.
Multidex, bien qu'efficace, devrait être évité si possible.
Comment éviter la limite:
Avant de configurer votre application pour permettre l'utilisation de références de méthode 64 Ko ou plus, vous devez prendre des mesures pour réduire le nombre total de références appelées par votre code d'application, y compris les méthodes définies par votre code d'application ou les bibliothèques incluses. Les stratégies suivantes peuvent vous aider à éviter d’atteindre la limite de référence dex:
- Examinez les dépendances directes et transitives de votre application - Assurez-vous que toute dépendance de bibliothèque importante que vous incluez dans votre application est utilisée d'une manière qui dépasse la quantité de code ajoutée à l'application. Un anti-pattern commun est d'inclure une très grande bibliothèque car quelques méthodes utilitaires étaient utiles. La réduction des dépendances du code de votre application peut souvent vous aider à éviter la limite de référence dex.
- Supprimez le code inutilisé avec ProGuard - Configurez les paramètres ProGuard pour que votre application exécute ProGuard et assurez-vous que la réduction des créations est activée. L'activation du rétrécissement garantit que vous ne livrez pas de code inutilisé avec vos APK.
Le premier point nécessite une diligence et une discipline de la part du développeur. Lors de l'intégration de bibliothèques tierces, il faut tenir compte de la taille de la bibliothèque. Par exemple, deux bibliothèques JSON populaires sont Jackson et Gson. Fonctionnellement, ils sont assez similaires, mais Gson a tendance à voir une plus grande utilisation dans Android. L’une des raisons est que Jackson pèse environ 9 000 méthodes, alors que Gson en contribue 1 900.
Plusieurs outils sont disponibles pour aider les développeurs à suivre la taille de leur application:
- dexcount-gradle-plugin indique le nombre de références de méthode dans votre APK ou AAR sur chaque version
- dex-method-count est un outil en ligne de commande qui compte le nombre de références de méthode dans un APK
- www.methodscount.com est un service Web qui comptera les références de méthode dans tout fichier APK que vous téléchargez.
Multidex en utilisant MultiDexApplication directement
Utilisez cette option si vous n'avez pas besoin d'une sous-classe d' Application
.
C'est l'option la plus simple, mais de cette façon, vous ne pouvez pas fournir votre propre sous-classe d' Application
. Si une sous-classe d' Application
est nécessaire, vous devrez passer à l'une des autres options pour le faire.
Pour cette option, spécifiez simplement le nom de classe complet android.support.multidex.MultiDexApplication
pour la propriété android:name
de la balise d' application
dans le fichier AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.multidex.myapplication">
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
</manifest>
Multidex en étendant l'application
Utilisez cette option si votre projet nécessite une sous-classe Application
.
Spécifiez cette sous-classe d' Application
à l'aide de la propriété android:name
dans le fichier manifeste de la balise d' application
.
Dans la sous-classe Application
, ajoutez la méthode attachBaseContext()
et, dans cette méthode, appelez MultiDex.install()
:
package com.example;
import android.app.Application;
import android.content.Context;
/**
* Extended application that support multidex
*/
public class MyApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
Assurez-vous que la sous-classe Application
est spécifiée dans la balise d' application
de votre AndroidManifest.xml:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>
Activation de Multidex
Pour activer une configuration multidex, vous avez besoin:
- changer votre configuration de build Gradle
- utiliser
MultiDexApplication
ou activer MultiDex dans votre classeApplication
Configuration de Gradle
Dans app/build.gradle
ajoutez ces parties:
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 24
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
Activer MultiDex dans votre application
Ensuite, effectuez l'une des trois options suivantes:
Lorsque ces paramètres de configuration sont ajoutés à une application, les outils de génération Android construisent un dex (classes.dex) principal et prennent en charge (classes2.dex, classes3.dex) selon les besoins.
Le système de compilation les intégrera ensuite dans un fichier APK pour la distribution.
Méthode de comptage Références sur chaque version (Dexcount Gradle Plugin)
Le plug-in dexcount compte les méthodes et le nombre de ressources de classe après une génération réussie.
Ajoutez le plugin dans l' app/build.gradle
:
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral() // or jcenter()
}
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
}
}
Appliquez le plugin dans le fichier app/build.gradle
:
apply plugin: 'com.getkeepsafe.dexcount'
Recherchez les données de sortie générées par le plug-in dans:
../app/build/outputs/dexcount
Le graphique .html est particulièrement utile dans:
../app/build/outputs/dexcount/debugChart/index.html
Multidex en étendant MultiDexApplication
Cela ressemble beaucoup à l'utilisation d'une sous-classe Application
et au attachBaseContext()
méthode attachBaseContext()
.
Cependant, en utilisant cette méthode, vous n'avez pas besoin de remplacer attachBaseContext()
car cela est déjà fait dans la super-classe MultiDexApplication
.
Étendez MultiDexApplication
au lieu de Application
:
package com.example;
import android.support.multidex.MultiDexApplication;
import android.content.Context;
/**
* Extended MultiDexApplication
*/
public class MyApplication extends MultiDexApplication {
// No need to override attachBaseContext()
//..........
}
Ajoutez cette classe à votre AndroidManifest.xml exactement comme si vous étendiez l'application:
<application
android:name="com.example.MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</application>