Impossible d'exécuter dex: l'ID de méthode n'est pas dans [0, 0xffff]: 65536

344

J'ai déjà vu différentes versions des err dex, mais celle-ci est nouvelle. nettoyer / redémarrer, etc. n'aidera pas. Les projets de bibliothèque semblent intacts et la dépendance semble être correctement liée.

Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

ou

Cannot merge new index 65950 into a non-jumbo instruction

ou

java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536

tl; dr : La solution officielle de Google est enfin là!

http://developer.android.com/tools/building/multidex.html

Une seule petite astuce, vous aurez probablement besoin de le faire pour éviter de manquer de mémoire lors de la dex-ing.

dexOptions {
        javaMaxHeapSize "4g"
}

Il existe également un mode jumbo qui peut résoudre ce problème de manière moins fiable:

dexOptions {
        jumboMode true
}

Mise à jour: si votre application est grasse et que vous avez trop de méthodes à l'intérieur de votre application principale, vous devrez peut-être réorganiser votre application selon

http://blog.osom.info/2014/12/too-many-methods-in-main-dex.html

Edison
la source
1
Utilisez-vous une API qui n'est pas disponible sur votre appareil actuel?
rekire
C'est là, car un autre projet se construit bien en ciblant la même version d'API.
Edison
Vous utilisez donc à un moment donné une API qui n'est pas disponible? Vérifiez-vous avec une ligne comme if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)celle-là que vous n'appelez pas cette fonction si elle n'est pas disponible?
rekire
Oui je fais. Le projet s'est bien construit avant. En outre, cela devrait être une erreur d'exécution même si j'ai raté la ligne.
Edison
C'est probablement l'une des dépendances qui est foirée. (en train de faire un mix de maven + project lib en ce moment)
Edison

Réponses:

379

Mise à jour 3 (11/3/2014)
Google a finalement publié la description officielle .


Mise à jour 2 (31/10/2014) Le
plugin Gradle v0.14.0 pour Android ajoute la prise en charge du multi-dex. Pour l'activer, il vous suffit de le déclarer dans build.gradle :

android {
   defaultConfig {
      ...
      multiDexEnabled  true
   }
}

Si votre application prend en charge Android avant 5.0 (c'est-à-dire si vous avez minSdkVersion20 ans ou moins), vous devez également corriger dynamiquement l' application ClassLoader , afin qu'elle puisse charger des classes à partir de dex secondaires. Heureusement, il y a une bibliothèque qui fait ça pour vous. Ajoutez-le aux dépendances de votre application:

dependencies {
  ...
  compile 'com.android.support:multidex:1.0.0'
} 

Vous devez appeler le code du correctif ClassLoader dès que possible. MultiDexApplicationLa documentation de la classe suggère trois façons de le faire (choisissez-en une , celle qui vous convient le mieux):

1 - Déclarez la MultiDexApplicationclasse comme application dans votre 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>

2 - Demandez à votre Applicationclasse d'étendre la classe MultiDexApplication :

public class MyApplication extends MultiDexApplication { .. }

3 - Appelez MultiDex#installdepuis votre Application#attachBaseContextméthode:

public class MyApplication {
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
        ....
    }
    ....
}

Mise à jour 1 (17/10/2014):
comme prévu, la prise en charge multidex est fournie dans la révision 21 de la bibliothèque de support Android. Vous pouvez trouver le dossier android-support-multidex.jar dans le dossier / sdk / extras / android / support / multidex / library / libs.


Le support multi-dex résout ce problème. dx 1.8 permet déjà de générer plusieurs fichiers dex.
Android L prendra en charge le multi-dex en natif, et la prochaine révision de la bibliothèque de support va couvrir les anciennes versions de retour à l'API 4.

Il a été déclaré dans cet épisode de podcast Android Developers Backstage par Anwar Ghuloum. J'ai posté une transcription (et une explication générale multi-dex) de la partie pertinente.

Alex Lipov
la source
2
le blog est un économiseur! : D
nadavfima
39
Quelque chose pour les utilisateurs d'Eclipse?
Muhammad Babar
52
@MuhammadBabar Il existe un studio Android pour les utilisateurs d'Eclipse.
VipulKumar
2
@MohammedAli Bien sûr, évitez de l'utiliser si vous le pouvez. Mais que devez-vous faire si vous avez vraiment trop de méthodes dans votre application et que vous avez déjà essayé toutes les astuces comme celle que vous avez mentionnée? Concernant le temps de construction - il y a une solution pour cela, au moins pour les builds de développement - voir ma réponse ici: stackoverflow.com/a/30799491/1233652
Alex Lipov
2
Sur Qt pour Android, j'avais des problèmes lors de l'exécution de mon application lors de l'intégration des SDK de Facebook + Twitter, même après avoir activé la prise en charge multidex (cette erreur en particulier m'a donné des cauchemars:) java.lang.ClassNotFoundException: Didn't find class "org.qtproject.qt5.android.QtActivityDelegate" on path: DexPathList[[],nativeLibraryDirectories=[/vendor/lib, /system/lib]]. Il s'est avéré que mon erreur était que je n'appliquais pas les étapes supplémentaires pour le support Android avant 5.0. Cela dit, l'option n ° 3 l'a résolu et je n'ai plus eu de ClassNotFoundExceptionproblème. Merci, @Alex Lipov!
voler
78

Comme déjà indiqué, vous avez trop de méthodes (plus de 65k) dans votre projet et vos librairies.

Prévention du problème: réduisez le nombre de méthodes avec Play Services 6.5+ et support-v4 24.2+

Depuis souvent, les services Google Play sont l'un des principaux suspects dans les méthodes de «gaspillage» avec ses méthodes 20k + . Services Google Play version 6.5 ou ultérieure, il vous est possible d'inclure des services Google Play dans votre application à l'aide d'un certain nombre de bibliothèques clientes plus petites. Par exemple, si vous n'avez besoin que de GCM et de cartes, vous pouvez choisir d'utiliser uniquement ces dépendances:

dependencies {
    compile 'com.google.android.gms:play-services-base:6.5.+'
    compile 'com.google.android.gms:play-services-maps:6.5.+'
}

La liste complète des sous-bibliothèques et de ses responsabilités se trouve dans le doc officiel de Google .

Mise à jour : depuis la bibliothèque de support v4 v24.2.0, elle a été divisée en modules suivants:

support-compat, support-core-utils, support-core-ui, support-media-compatEtsupport-fragment

dependencies {
    compile 'com.android.support:support-fragment:24.2.+'
}

Notez cependant que si vous utilisez support-fragment, il aura des dépendances avec tous les autres modules (c.-à-d. Si vous utilisez android.support.v4.app.Fragmentil n'y a aucun avantage)

Voir ici les notes de version officielles de support-v4 lib


Activer MultiDexing

Depuis Lollipop (aka build tools 21+), il est très facile à manipuler. L'approche consiste à contourner le problème des méthodes 65k par fichier dex pour créer plusieurs fichiers dex pour votre application. Ajoutez ce qui suit à votre fichier de construction Gradle ( cela provient du document officiel de Google sur les applications avec plus de 65 000 méthodes ):

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig {
        ...
        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.1'
}

La deuxième étape consiste à préparer votre classe d'application ou, si vous ne développez pas l'application, utilisez le MultiDexApplicationdans votre manifeste Android:

Soit ajoutez ceci à votre Application.java

@Override
  protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(this);
  }

ou utilisez l'application fournie à partir de la bibliothèque mutlidex

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

Empêcher OutOfMemory avec MultiDex

Comme autre conseil, si vous rencontrez des OutOfMemoryexceptions pendant la phase de construction, vous pouvez agrandir le tas avec

android {
    ...
    dexOptions {
        javaMaxHeapSize "4g"
    }
}

ce qui mettrait le tas à 4 gigaoctets.

Consultez cette question pour plus de détails sur le problème de la mémoire de tas dex.


Analyser la source du problème

Pour analyser la source des méthodes, le plugin gradle https://github.com/KeepSafe/dexcount-gradle-plugin peut aider en combinaison avec l'arbre de dépendance fourni par gradle avec par exemple

.\gradlew app:dependencies

Voir cette réponse et cette question pour plus d'informations sur le nombre de méthodes dans Android

Patrick Favre
la source
J'ai utilisé la solution Play Services 6.5+ et cela a parfaitement fonctionné. Conseil utile incroyable. Merci beaucoup!
Hoang Nguyen Huu
Je voterais davantage si je le pouvais - en supprimant tous les autres éléments des services de jeu que nous n'utilisions pas, nous avons résolu ce problème, sans avoir à recourir au multi-dex, ce qui a des implications négatives sur les performances lors de la construction.
Sean Barbeau
1
Que toi, les larmes aux yeux. Tu m'as sauvé
insomniaque
J'ai utilisé la bibliothèque cliente pour GCM, car j'utilise uniquement le service gcm du service de lecture, maintenant cela a résolu mon problème avec cela. Merci! pour gagner mon temps.
Ankit
57

Votre projet est trop grand. Vous avez trop de méthodes. Il ne peut y avoir que 65536 méthodes par application. voir ici https://code.google.com/p/android/issues/detail?id=7147#c6

blobbie
la source
Je vois. J'ai beaucoup de dépendances pour ce projet. Cela fonctionne bien avant de passer à l'utilisation de maven, peut-être que maven a ajouté des dépendances inutiles. Va vérifier.
Edison
5
Pour être plus précis, il ne peut y avoir que 65 536 méthodes par fichier exécutable Dalvik (dex). Et une application (APK) peut avoir plus d'un fichier dex avec des choses telles que le chargement personnalisé.
Dennis Sheil
7
C'est vraiment un bug embarrassant pour Android! Quoi qu'il en soit, dans mon cas, j'ai supprimé Jar qui était dans les bibliothèques et n'était pas utilisé, et l'application a été compilée
David
Il est temps de nettoyer mon projet: /
Leurre
1
Une solution rapide serait d'utiliser Proguard aussi avec le debug
Aleb
12

Le code ci-dessous est utile si vous utilisez Gradle. Vous permet de supprimer facilement les services Google inutiles (en supposant que vous les utilisez) pour revenir en dessous du seuil de 65k. Tous les crédits à ce poste: https://gist.github.com/dmarcato/d7c91b94214acd936e42

Edit 2014-10-22 : Il y a eu beaucoup de discussions intéressantes sur l'essentiel référencé ci-dessus. TLDR? regard sur celui - ci: https://gist.github.com/Takhion/10a37046b9e6d259bb31

Collez ce code au bas de votre fichier build.gradle et ajustez la liste des services google dont vous n'avez pas besoin:

def toCamelCase(String string) {
    String result = ""
    string.findAll("[^\\W]+") { String word ->
        result += word.capitalize()
    }
    return result
}

afterEvaluate { project ->
    Configuration runtimeConfiguration = project.configurations.getByName('compile')
    ResolutionResult resolution = runtimeConfiguration.incoming.resolutionResult
    // Forces resolve of configuration
    ModuleVersionIdentifier module = resolution.getAllComponents().find { it.moduleVersion.name.equals("play-services") }.moduleVersion

    String prepareTaskName = "prepare${toCamelCase("${module.group} ${module.name} ${module.version}")}Library"
    File playServiceRootFolder = project.tasks.find { it.name.equals(prepareTaskName) }.explodedDir

    Task stripPlayServices = project.tasks.create(name: 'stripPlayServices', group: "Strip") {
        inputs.files new File(playServiceRootFolder, "classes.jar")
        outputs.dir playServiceRootFolder
        description 'Strip useless packages from Google Play Services library to avoid reaching dex limit'

        doLast {
            copy {
                from(file(new File(playServiceRootFolder, "classes.jar")))
                into(file(playServiceRootFolder))
                rename { fileName ->
                    fileName = "classes_orig.jar"
                }
            }
            tasks.create(name: "stripPlayServices" + module.version, type: Jar) {
                destinationDir = playServiceRootFolder
                archiveName = "classes.jar"
                from(zipTree(new File(playServiceRootFolder, "classes_orig.jar"))) {
                    exclude "com/google/ads/**"
                    exclude "com/google/android/gms/analytics/**"
                    exclude "com/google/android/gms/games/**"
                    exclude "com/google/android/gms/plus/**"
                    exclude "com/google/android/gms/drive/**"
                    exclude "com/google/android/gms/ads/**"
                }
            }.execute()
            delete file(new File(playServiceRootFolder, "classes_orig.jar"))
        }
    }

    project.tasks.findAll { it.name.startsWith('prepare') && it.name.endsWith('Dependencies') }.each { Task task ->
        task.dependsOn stripPlayServices
    }
}
mcm
la source
Aimer! def nécessaire car des entreprises comme Google continuent de gonfler les packages.
Edison
1
Bien - cela a fait l'affaire. Pas de soucis et pas de soucis!
slott
Remarque: ces fichiers supprimés des services Google Play dans mon SDK Android dans Android Studio! Une mauvaise idée car il n'est pas facile de revenir aux pots d'origine. L'auteur doit modifier le script pour changer les fichiers JAR dans le répertoire de construction.
inder
@inder: Je n'ai pas eu ce problème. Cependant, je devais faire un cleanchaque fois que je singe avec les exclus (nous utilisons des analyses).
JohnnyLambada
comment exclure cela des versions de version?
user1324936
6

J'ai partagé un exemple de projet qui résout ce problème en utilisant le script de construction custom_rules.xml et quelques lignes de code.

Je l'ai utilisé sur mon propre projet et il fonctionne parfaitement sur les appareils 1M + (d'Android-8 au dernier Android-19). J'espère que cela aide.

https://github.com/mmin18/Dex65536

mmin
la source
1
Merci pour les scripts. vous devez faire attention à ART. L'appareil peut convertir uniquement votre dex par défaut et non les secondaires. Les solutions Proguard doivent être privilégiées.
Edison
2
Lorsque j'importe les projets dans Eclipse et que je l'exécute, cela donne une erreur. "Impossible d'exécuter dex: l'ID de méthode n'est pas dans [0, 0xffff]: 65536". Pouvez-vous expliquer l'utilisation du projet
Karacago
6

J'ai rencontré le même problème et l'ai résolu en modifiant mon fichier build.gradle dans la section des dépendances, en supprimant:

compile 'com.google.android.gms:play-services:7.8.0'

Et en le remplaçant par:

compile 'com.google.android.gms:play-services-location:7.8.0'
compile 'com.google.android.gms:play-services-analytics:7.8.0' 
Luis Miguel Ballestas
la source
Parfait! J'utilise simplement l'API Google Drive et cela fonctionne.
vedavis
5

Essayez d'ajouter le code ci-dessous dans build.gradle, cela a fonctionné pour moi -

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}
Sunita
la source
2

La solution parfaite pour cela serait de travailler avec Proguard. comme Aleb mentionné dans le commentaire. Cela réduira de moitié la taille du fichier dex.

shimi_tap
la source
1
D'accord, avec un pot de services google play de plus en plus important en particulier * (méthodes 18k en soi)
Edison
2

Vous pouvez analyser le problème (références de fichiers dex) à l'aide d'Android Studio:

Créer -> Analyser APK ..

Dans le panneau de résultats, cliquez sur le fichier classes.dex

Et vous verrez:

entrez la description de l'image ici

alexshr
la source
0

solution gradle + proguard:

afterEvaluate {
  tasks.each {
    if (it.name.startsWith('proguard')) {
        it.getInJarFilters().each { filter ->
            if (filter && filter['filter']) {
                filter['filter'] = filter['filter'] +
                        ',!.readme' +
                        ',!META-INF/LICENSE' +
                        ',!META-INF/LICENSE.txt' +
                        ',!META-INF/NOTICE' +
                        ',!META-INF/NOTICE.txt' +
                        ',!com/google/android/gms/ads/**' +
                        ',!com/google/android/gms/cast/**' +
                        ',!com/google/android/gms/games/**' +
                        ',!com/google/android/gms/drive/**' +
                        ',!com/google/android/gms/wallet/**' +
                        ',!com/google/android/gms/wearable/**' +
                        ',!com/google/android/gms/plus/**' +
                        ',!com/google/android/gms/topmanager/**'
            }
        }
    }
  }
}
Oleg Khalidov
la source
0

Supprimez un fichier jar du dossier Libs et copiez-le dans un autre dossier, puis accédez à _Project Properties> Select Java Build Path, Select Libraries, Select Add External Jar, Select the Removed jar to your project, Click save, this will be added under Referenced Bibliothèque au lieu du dossier Libs. Maintenant, nettoyez et exécutez votre projet. Vous n'avez pas besoin d'ajouter de code pour MultDex. Cela a simplement fonctionné pour moi.

Lakshmanan
la source
0

J'étais confronté au même problème aujourd'hui, ce qui a fonctionné est en dessous

Pour ANDROID STUDIO ... Activer l'exécution instantanée

Dans Fichier-> Préférences-> Build, Execution, Deployment-> Instant Run-> Cochez Enable Instant run for hot swap ...

J'espère que cela aide

Abdul Waheed
la source
1
Cela a fonctionné pour moi - j'ai simplement désactivé Enable Run, cliqué sur Appliquer, réactivé, et cela a fonctionné à nouveau.
MrBigglesworth