Неможливо виконати ідентифікатор dex: методу не в [0, 0xffff]: 65536


344

Раніше я бачив різні версії помилок Dex, але ця нова. очищення / перезапуск тощо не допоможе. Бібліотечні проекти здаються недоторканими, а залежність, здається, пов’язана правильно.

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

або

Cannot merge new index 65950 into a non-jumbo instruction

або

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

tl; dr : Офіційне рішення від Google нарешті тут!

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

Лише одна невелика порада, вам, ймовірно, потрібно буде це зробити, щоб уникнути втрати пам’яті під час декс-інгу.

dexOptions {
        javaMaxHeapSize "4g"
}

Є також джембовий режим, який може виправити це менш надійним способом:

dexOptions {
        jumboMode true
}

Оновлення: Якщо у вашому додатку жир, і у вас є занадто багато методів у вашому головному додатку, можливо, вам доведеться повторно організувати додаток відповідно до

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


1
Чи використовуєте ви api, який не є доступним для вашого поточного пристрою?
— rekire

Це там, тому що інший проект створює чітку орієнтацію на ту ж версію API.
— Едісон

Отже, ви використовуєте в якийсь момент API, який недоступний? Чи перевіряєте ви такою лінією, if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)що ви не викликаєте цю функцію, якщо її немає?
— rekire

Так, я. Проект будувався чудово раніше. Також це має бути помилкою виконання, навіть якщо я пропустив рядок.
— Едісон

Мабуть, одна із залежностей заплутана. (зараз робимо суміш Maven + Project lib)
— Едісон

Відповіді:


379

Оновлення 3 (3.11.2014)
Google нарешті опублікував офіційний опис .


Оновлення 2 (31.10.2014)
плагін Gradle v0.14.0 для Android додає підтримку мультидекса. Щоб увімкнути, потрібно просто оголосити це у build.gradle :

android {
   defaultConfig {
      ...
      multiDexEnabled  true
   }
}

Якщо ваш додаток підтримує Android до 5.0 (тобто якщо вам minSdkVersion20 або менше), вам також доведеться динамічно виправляти додаток ClassLoader , тож він зможе завантажувати класи з вторинних дексі. На щастя, є бібліотека, яка робить це для вас. Додайте його до залежностей свого додатка:

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

Вам потрібно якнайшвидше зателефонувати до патч-коду ClassLoader. ДокументаціяMultiDexApplication класу пропонує три способи зробити це (виберіть один із них , найзручніший для вас):

1 - оголосити MultiDexApplicationклас додатком у 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 - Попросіть ваш Applicationклас розширити клас MultiDexApplication :

public class MyApplication extends MultiDexApplication { .. }

3 - Телефонуйте MultiDex#installзі свого Application#attachBaseContextметоду:

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

Оновлення 1 (17.10.2014):
Як очікувалося, підтримка мультидекса надається у версії 21 Бібліотеки підтримки Android. Ви можете знайти android-support-multidex.jar у / sdk / extras / android / support / multidex / library / libs.


Підтримка Multi-dex вирішує цю проблему. dx 1.8 вже дозволяє генерувати кілька файлів dex.
Android L підтримуватиме мультидексні програми, і наступна версія бібліотеки підтримки охопить старіші версії назад до API 4.

Про це було сказано в цьому епізоді про подкаст Android Developers Backstage Anwar Ghuloum. Я опублікував стенограму (та загальне мультидекстне пояснення) відповідної частини.


2
повідомлення в блозі - це заощадження! : D
— надавфіма

39
Що-небудь для користувачів затемнення?
— Мухаммед Бабар

52
@MuhammadBabar Існує Android-студія для користувачів Eclipse.
— VipulKumar

2
@MohammedAli Звичайно, уникай його використання, якщо зможеш. Але що робити, якщо у вашому додатку дійсно занадто багато методів, і ви вже випробували всі хитрощі, як той, про який ви згадали? Щодо часу збирання - для цього є рішення, принаймні, для розробок для розвитку - дивіться мою відповідь тут: stackoverflow.com/a/30799491/1233652
— Alex Lipov

2
У Qt для Android у мене виникли проблеми під час інтегрування програми для мого додатка, навіть коли було інтегровано SDK-файли Facebook + Twitter разом, навіть після ввімкнення підтримки мультидекса (зокрема ця помилка дала мені кошмари:) java.lang.ClassNotFoundException: Didn't find class "org.qtproject.qt5.android.QtActivityDelegate" on path: DexPathList[[],nativeLibraryDirectories=[/vendor/lib, /system/lib]]. Виявилося, що моя помилка полягала в тому, що я не застосовував додаткові кроки для підтримки Android до 5.0. З урахуванням сказаного, варіант №3 вирішив це, і у мене більше не було ClassNotFoundExceptionпроблем. Дякую, @Alex Lipov!
— пограбувати

78

Як уже було сказано, у вас є занадто багато методів (більше 65 к) в своєму проекті.

Запобігання проблемі. Зменшіть кількість методів за допомогою Play Services 6.5+ та support-v4 24.2+

Оскільки часто сервіси Google Play є одним з головних підозрюваних у "витрачанні" методів із її методами 20k + . Служби Google Play версії 6.5 або новішої версії, ви можете включити служби Google Play у свою програму за допомогою декількох менших бібліотек клієнтів. Наприклад, якщо вам потрібні лише GCM та карти, ви можете використовувати лише ці залежності:

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

Повний перелік під бібліотек та його обов'язки можна знайти в офіційному документі google .

Оновлення : Оскільки Бібліотека підтримки v4 v24.2.0, вона була розділена на наступні модулі:

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

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

Однак зауважте, якщо ви використовуєте support-fragment, це матиме залежність від усіх інших модулів (тобто, якщо ви використовуєте, android.support.v4.app.Fragmentнемає ніякої користі)

Дивіться тут офіційні примітки до випуску для support-v4 lib


Увімкнути MultiDexing

Оскільки Lollipop (він же інструменти для збирання 21+) впоратися з ним дуже просто. Підхід полягає в тому, щоб вирішити проблему з методом 65k на файл dex, щоб створити кілька файлів dex для вашої програми. Додайте до файлу збірки gradle наступне ( це взято з офіційного документа google для додатків із більш ніж 65 к методами ):

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

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

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

Другий крок - або підготувати клас програми, або якщо ви не розширюєте програму, використовуйте на MultiDexApplicationсвоєму Manifest Android:

Або додайте це до свого Application.java

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

або скористайтеся наданою програмою від lili 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>

Запобігання OutOfMemory за допомогою MultiDex

В якості подальшої підказки, якщо ви зіткнетесь з OutOfMemoryвинятками під час фази збірки, ви можете збільшити купу

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

який би встановив купу до 4 гігабайт.

Дивіться це запитання для більш детальної інформації щодо проблеми пам'яті Dex.


Проаналізуйте джерело проблеми

Щоб проаналізувати джерело методів, плагін gradle https://github.com/KeepSafe/dexcount-gradle-plugin може допомогти в поєднанні з деревом залежностей, наданим gradle з, наприклад,

.\gradlew app:dependencies

Дивіться цю відповідь та питання для отримання додаткової інформації про кількість методів в android


Я використовував рішення Play Services 6.5+ і воно працювало чудово. Неймовірна корисна порада. Дуже дякую!
— Hoang Nguyen Huu

Я б подав більше пропозицій, якщо б міг - вирізати всі інші речі Play Services, які ми не використовували, виправили цю проблему, не вдаючись до мультидекса, що має негативні наслідки для продуктивності при побудові.
— Шон Барбо

1
Чим ти стільки зі сльозами на очах. Ти врятував мене
— безсоння

Я використовував клієнтську бібліотеку для GCM, тому що я використовую лише сервіси gcm з сервісу відтворення, тепер це вирішило мою проблему. Дякую! щоб заощадити свій час.
— Анкіт

57

Ваш проект занадто великий. У вас занадто багато методів. На одну заявку може бути лише 65536 методів. дивіться тут https://code.google.com/p/android/isissue/detail?id=7147#c6


Розумію. У мене дуже багато залежностей від цього проекту. Це добре працює, перш ніж я перейшов до використання Maven, хоча, можливо, Maven додав зайві залежності. Повторимо перевірку.
— Едісон

5
Щоб бути більш конкретним, на виконуваний (dex) файл Dalvik може бути лише 65 536 методів. І додаток (APK) може мати декілька файлів dex з такими речами, як завантаження на замовлення.
— Денніс Шейл

7
Це справді бентежно помилка для андроїда! У будь-якому випадку, у мені випадку я видалив Jar, який був у лійках і не використовувався, і додаток складено
— Девід

Час, щоб почистити мій проект: /
— Decoy

1
Швидким виправленням буде використання Proguard також із налагодженнями налагодження
— aleb

12

Наведений нижче код допоможе, якщо ви використовуєте Gradle. Дозволяє легко видаляти непотрібні служби Google (припускаючи, що ви ними користуєтесь), щоб повернутися нижче порогу 65 к. Вся заслуга в цій публікації: https://gist.github.com/dmarcato/d7c91b94214acd936e42

Редагувати 2014-10-22 : Про суть, про яку згадувалося вище, було багато цікавої дискусії. TLDR? дивіться на це: https://gist.github.com/Takhion/10a37046b9e6d259bb31

Вставте цей код у нижній частині файлу build.gradle та відрегулюйте список служб Google, які вам не потрібні:

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
    }
}

Любіть це! Def потрібні, оскільки такі компанії, як Google, продовжують надувати пакунки.
— Едісон

1
Приємно - це було місце роботи. Без клопоту і ніяких турбот!
— слот

Примітка. Ця видалена баночка служб Google Play в моїй SDK для Android в Android Studio! Погана ідея, оскільки повернутись до оригінальних баночок непросто. Автор повинен змінити сценарій, щоб змінити банки в каталозі збірки.
— індер

@inder: У мене не було такої проблеми. Однак мені довелося робити cleanщоразу, коли я маніпулював виключеннями (ми використовуємо аналітику).
— JohnnyLambada

як виключити це з версій версій?
— user1324936

6

Я поділився зразковим проектом, який вирішує цю проблему за допомогою сценарію збірки custom_rules.xml та кількох рядків коду.

Я використовував його у власному проекті, і він працює бездоганно на пристроях 1M + (від android-8 до останнього android-19). Сподіваюся, це допомагає.

https://github.com/mmin18/Dex65536


1
Дякуємо за сценарії. ви повинні стежити за АРТ. Пристрій може конвертувати лише ваш декс за замовчуванням, а не вторинний. Слід віддати перевагу прогуардним рішенням.
— Едісон

2
Коли я імпортую проекти у Eclipse та запускаю, це дає помилку. "Неможливо виконати ідентифікатор dex: методу не в [0, 0xffff]: 65536". Чи можете ви пояснити використання проекту
— Каракаго

6

Зіткнувся з тією ж проблемою і вирішив її, відредагувавши мій файл build.gradle в розділі залежності, видаливши:

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

І замінивши його на:

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

Ідеально! Я просто використовую API Google Drive, і це працює.
— vedavis

5

Спробуйте додати код нижче в build.gradle, він працював для мене -

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}

2

Ідеальним рішенням для цього буде робота з Proguard. як алеб згаданий у коментарі. Це зменшить розмір файлу dex вдвічі.


1
Домовились, особливо з все більш масштабним баночкою служб Google Play * (18-ти методів самотужки)
— Едісон,

2

Ви можете проаналізувати проблему (посилання на файли dex) за допомогою Android Studio:

Збірка -> Аналіз APK ..

На панелі результатів натисніть файл class.dex

І ви побачите:

введіть тут опис зображення


0

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

Видаліть якийсь файл jar із папки Libs та скопіюйте у якусь іншу папку та перейдіть до _Project Properties> Виберіть Java Build Path, Select Libraries, Select Add External Jar, Select Remoted jar to your project, Click save, це буде додано у розділі Посилання Бібліотека замість папки Libs. Тепер очистіть і запустіть свій проект. Вам не потрібно додавати будь-який код для MultDex. Це просто працювало для мене.


0

Я сьогодні стикався з тим же питанням, над чим працював, - знизу

Для ANDROID STUDIO ... Увімкніть миттєвий запуск

У меню Файл-> Налаштування-> Збірка, виконання, розгортання-> Миттєвий запуск-> Перевірити Увімкнути миттєвий запуск для гарячої заміни ...

Сподіваюся, це допомагає


1
Це працювало для мене - я просто відключив Увімкнути запуск, натиснув Застосувати, повторно ввімкнув його, і він знову працював.
— MrBigglesworth
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.