web-dev-qa-db-fra.com

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

J'ai déjà vu diverses versions des erreurs dex, mais celle-ci est nouvelle. nettoyer/redémarrer, etc. ne vous aidera pas. Les projets de bibliothèque semblent intacts et les dépendances semblent être correctement liées.

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 arrivée!

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

Une petite astuce, vous aurez probablement besoin de le faire pour éviter le manque de mémoire lorsque vous effectuez dux-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 dans votre application principale, vous devrez peut-être réorganiser votre application selon les instructions.

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

339
Edison

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


Mise à jour 2 (31/10/2014)
Gradle plugin v0.14.0 pour Android ajoute le support pour multi-dex. Pour l'activer, il 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 votre minSdkVersion vaut 20 ou moins), vous devez également appliquer un correctif dynamique à l'application ClassLoader , il pourra donc charger des classes à partir dex secondaires. Heureusement, il existe une bibliothèque qui le fait pour vous. Ajoutez-le aux dépendances de votre application:

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

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

1 - Déclarez MultiDexApplication class 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 - Votre classe Application est-elle étendue MultiDexApplication classe:

public class MyApplication extends MultiDexApplication { .. }

3 - Appelez MultiDex#install à partir de votre méthode Application#attachBaseContext:

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

Mise à jour 1 (17/10/2014):
Comme prévu, support multidex est fourni avec la révision 21 de Android Bibliothèque de support. Vous pouvez trouver le fichier 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 multi-dex de manière native, et la prochaine révision de la bibliothèque de support couvrira les versions plus anciennes de l’API 4.

Il a été déclaré dans this Android Les développeurs ont réalisé un épisode de podcast par Anwar Ghuloum. J'ai posté une transcription (et une explication générale multi-dex) de la partie pertinente.

374
Alex Lipov

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

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

Depuis souvent les services de Google Play sont l’un des principaux suspects dans les méthodes de "gaspillage" avec ses méthodes 20k + . Les services Google Play, version 6.5 ou ultérieure, vous permettent d'inclure les services Google Play de votre application utilisent un certain nombre de bibliothèques clientes plus petites. Par exemple, si vous avez uniquement besoin de MCG et de cartes, vous pouvez choisir de: utilisez ces dépendances uniquement:

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 ses responsabilités peuvent être trouvées dans le document officiel de Google .

Mise à jour : Depuis Support Library v4 v24.2.0, il a été divisé en modules:

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

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

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

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


Activer le 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 les éléments suivants à votre fichier de construction Gradle ( extrait du document officiel Google concernant les applications comportant 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 n’étendez pas Application, à utiliser le MultiDexApplication de votre manifeste Android:

Ajoutez-le à 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>

Prévenez OutOfMemory avec MultiDex

Comme autre astuce, si vous rencontrez des exceptions OutOfMemory au cours de la phase de construction, vous pouvez agrandir le tas avec

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

ce qui définirait le tas à 4 gigaoctets.

Voir cette question pour plus de détails sur le problème de 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 à combiner 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

77
patrickf

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

57
blobbie

Le code ci-dessous aide si vous utilisez Gradle. Vous permet de supprimer facilement les services Google inutiles (en supposant que vous les utilisiez) pour revenir en dessous du seuil de 65 000 $. Tout crédit à ce message: https://Gist.github.com/dmarcato/d7c91b94214acd936e42

Edit 2014-10-22 : Il y a eu beaucoup de discussions intéressantes sur le Gist mentionné ci-dessus. TLDR? regardez 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
    }
}
12
mcm

Face au même problème et résolu en modifiant mon fichier build.gradle dans la section dependencies, 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' 
6

J'ai partagé un exemple de projet qui résout ce problème à l'aide du script de génération custom_rules.xml et de 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 ça aide.

https://github.com/mmin18/Dex65536

6
mmin

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

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}
5
Sunita

Vous pouvez analyser le problème (références de fichier Dex) à l’aide de Android Studio:

Construire -> Analyser APK ..

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

Et vous verrez:

enter image description here

2
alexshr

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

2
shimi_tap

Supprimez un fichier jar du dossier Libs et copiez-le dans un autre dossier. Accédez ensuite à Propriétés du projet> Sélectionnez Java chemin de construction, sélectionnez bibliothèques, sélectionnez Ajouter un fichier jar externe, sélectionnez le fichier jar supprimé de votre projet, cliquez sur Enregistrer. être ajouté sous Bibliothèque référencée au lieu du dossier Libs. Maintenant, nettoyez et lancez votre projet. Vous n'avez pas besoin d'ajouter de code Any pour MultDex. Cela a tout simplement fonctionné pour moi.

0
Lakshmanan

Je faisais face au même problème aujourd'hui, ce qui a fonctionné est en bas

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

Dans Fichier-> Préférences-> Génération, Exécution, Déploiement-> Exécution instantanée-> Vérifier Activer l'exécution instantanée pour le remplacement à chaud ...

J'espère que ça aide

0
Abdul Waheed

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/**'
            }
        }
    }
  }
}
0
Oleg Khalidov