Nie można wykonać dex: identyfikator metody nie w [0, 0xffff]: 65536


344

Wcześniej widziałem różne wersje erozji dex, ale ta jest nowa. czyszczenie / restart itp. nie pomoże. Projekty bibliotek wydają się nienaruszone, a zależność wydaje się być poprawnie powiązana.

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

lub

Cannot merge new index 65950 into a non-jumbo instruction

lub

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

tl; dr : Oficjalne rozwiązanie Google jest już dostępne!

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

Tylko jedna mała wskazówka, prawdopodobnie będziesz musiał to zrobić, aby uniknąć braku pamięci podczas wykonywania deksowania.

dexOptions {
        javaMaxHeapSize "4g"
}

Istnieje również tryb jumbo, który może to naprawić w mniej niezawodny sposób:

dexOptions {
        jumboMode true
}

Aktualizacja: jeśli Twoja aplikacja jest gruba i masz zbyt wiele metod w głównej aplikacji, może być konieczne jej ponowne uporządkowanie zgodnie z

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


1
Czy używasz interfejsu API, który nie jest dostępny na twoim currient device?
— rekire

Jest tam, ponieważ inny projekt dobrze kompiluje celowanie w tę samą wersję API.
— Edison,

Więc w pewnym momencie używasz interfejsu API, który nie jest dostępny? Czy za pomocą takiej linii if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)nie wywołujesz tej funkcji, jeśli nie jest ona dostępna?
— rekire

Tak, zrobię. Projekt wcześniej był dobrze zbudowany. Powinien to być także błąd czasu wykonywania, nawet jeśli przegapiłem linię.
— Edison,

Prawdopodobnie jedna z zależności jest pomieszana. (robi teraz połączenie maven + lib projektu)
— Edison

Odpowiedzi:


379

Aktualizacja 3 (11.03.2014)
Google w końcu wydała oficjalny opis .


Aktualizacja 2 (
31.10.2014 ) Wtyczka Gradle v0.14.0 dla Androida dodaje obsługę multi-dex. Aby włączyć, wystarczy zadeklarować to w build.gradle :

android {
   defaultConfig {
      ...
      multiDexEnabled  true
   }
}

Jeśli Twoja aplikacja obsługuje system Android w wersji wcześniejszej niż 5.0 (to znaczy, jeśli masz minSdkVersion20 lat lub mniej), musisz także dynamicznie załatać aplikację ClassLoader , aby móc ładować klasy z pobocznych instrukcji. Na szczęście istnieje biblioteka, która robi to za Ciebie. Dodaj go do zależności aplikacji:

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

Musisz jak najszybciej wywołać kod poprawki ClassLoader. dokumentacjaMultiDexApplication klasy sugeruje trzy sposoby na zrobienie tego (wybierz jeden z nich , który jest dla ciebie najwygodniejszy):

1 - Zadeklaruj MultiDexApplicationklasę jako aplikację w pliku 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 - Poproś swoją Applicationklasę o rozszerzenie klasy MultiDexApplication :

public class MyApplication extends MultiDexApplication { .. }

3 - Wywołanie MultiDex#installz Twojej Application#attachBaseContextmetody:

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

Aktualizacja 1 (10/17/2014):
Zgodnie z oczekiwaniami, obsługa multideksów jest dostarczana w wersji 21 Biblioteki pomocy technicznej Androida. Plik android-support-multidex.jar można znaleźć w folderze / sdk / extras / android / support / multidex / library / libs.


Obsługa Multi-dex rozwiązuje ten problem. dx 1.8 już pozwala na generowanie kilku plików dex.
Android L będzie obsługiwał natywnie multi-dex, a kolejna wersja biblioteki wsparcia obejmie starsze wersje z powrotem do API 4.

Stwierdzono w tym odcinku podcastu dla programistów Androida, przygotowanym przez Anwara Ghulouma. Mam napisali zapis (i ogólny multi-dex wyjaśnienia) odpowiedniej części.


2
post na blogu to oszczędność! : D
— nadavfima,

39
Coś dla użytkowników zaćmienia?
— Muhammad Babar

52
@MuhammadBabar Dla użytkowników Eclipse istnieje studio Android.
— VipulKumar

2
@MohammedAli Na pewno unikaj używania go, jeśli możesz. Ale co powinieneś zrobić, jeśli naprawdę masz zbyt wiele metod w swojej aplikacji i wypróbowałeś już wszystkie sztuczki, takie jak te, o których wspomniałeś? Jeśli chodzi o czas kompilacji - istnieje na to rozwiązanie, przynajmniej w przypadku kompilacji programistycznych - zobacz moją odpowiedź tutaj: stackoverflow.com/a/30799491/1233652
— Alex Lipov

2
W Qt na Androida miałem problemy z uruchomieniem mojej aplikacji podczas integracji SDK z Facebooka + Twittera, nawet po włączeniu obsługi multideksów (ten jeden błąd w szczególności dał mi koszmary:) java.lang.ClassNotFoundException: Didn't find class "org.qtproject.qt5.android.QtActivityDelegate" on path: DexPathList[[],nativeLibraryDirectories=[/vendor/lib, /system/lib]]. Okazało się, że mój błąd polegał na tym, że nie stosowałem dodatkowych kroków do obsługi Androida przed wersją 5.0. Powiedziawszy to, opcja nr 3 rozwiązała ten problem i nie miałem już ClassNotFoundExceptionproblemów. Dzięki, @Alex Lipov!
— okradać

78

Jak już wspomniano, masz zbyt wiele metod (ponad 65 000) w swoim projekcie i bibliotekach.

Zapobiegaj problemowi: zmniejsz liczbę metod dzięki Play Services 6.5+ i support-v4 24.2+

Ponieważ często usługi Google Play są jednym z głównych podejrzanych w „marnowaniu” metod za pomocą metod 20k + . Usługi Google Play w wersji 6.5 lub nowszej, możesz włączyć usługi Google Play do swojej aplikacji przy użyciu kilku mniejszych bibliotek klienckich. Na przykład, jeśli potrzebujesz tylko GCM i map, możesz użyć tylko tych zależności:

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

Pełna lista podbibliotek i ich obowiązków znajduje się w oficjalnym dokumencie Google .

Aktualizacja : Od czasu Support Library v4 v24.2.0 został podzielony na następujące moduły:

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

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

Pamiętaj jednak, że jeśli użyjesz support-fragment, będzie to zależało od wszystkich innych modułów (tj. Jeśli użyjeszandroid.support.v4.app.Fragment nie ma korzyści)

Zobacz tutaj oficjalne informacje o wydaniu lib support-v4


Włącz MultiDexing

Ponieważ Lollipop (inaczej narzędzia do kompilacji 21+) jest bardzo łatwy w obsłudze. Podejście polega na obejściu 65 000 metod na problem z plikiem dex, aby utworzyć wiele plików dex dla aplikacji. Dodaj następujące elementy do pliku kompilacji stopni ( jest to wzięte z oficjalnego dokumentu Google w aplikacjach z ponad 65k metodami ):

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

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

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

Drugim krokiem jest przygotowanie klasy aplikacji lub jeśli nie rozszerzysz aplikacji, skorzystaj z MultiDexApplicationmanifestu Android:

Dodaj to do pliku Application.java

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

lub użyj dostarczonej aplikacji z biblioteki 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>

Zapobiegaj OutOfMemory dzięki MultiDex

Dalszą wskazówką jest to, że jeśli napotkasz OutOfMemorywyjątki podczas fazy kompilacji, możesz powiększyć stos

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

co ustawiłoby stos na 4 gigabajty.

Zobacz to pytanie, aby uzyskać więcej informacji na temat problemu z pamięcią sterty dex.


Przeanalizuj źródło problemu

Aby przeanalizować źródło metod, wtyczka gradle https://github.com/KeepSafe/dexcount-gradle-plugin może pomóc w połączeniu z drzewem zależności udostępnionym przez gradle np.

.\gradlew app:dependencies

Zobacz tę odpowiedź i pytanie, aby uzyskać więcej informacji na temat liczby metod w Androidzie


Korzystałem z rozwiązania Play Services 6.5+ i działało ono doskonale. Niesamowita przydatna wskazówka. Dzięki wielkie!
— Hoang Nguyen Huu

Głosowałbym więcej, gdybym mógł - wycięcie wszystkich innych usług Play, z których nie korzystaliśmy, rozwiązało ten problem, bez konieczności uciekania się do multi-dex, co ma negatywny wpływ na wydajność podczas budowania.
— Sean Barbeau,

1
Tak bardzo ze łzami w oczach. Uratowałeś mnie
— bezsenność

Użyłem biblioteki klienta dla GCM, ponieważ używam tylko usługi gcm z usługi odtwarzania, teraz rozwiązało to mój problem. Dzięki! aby zaoszczędzić mój czas.
— Ankit

57

Twój projekt jest za duży. Masz za dużo metod. Może być tylko 65536 metod na aplikację. zobacz tutaj https://code.google.com/p/android/issues/detail?id=7147#c6


Widzę. Mam wiele zależności dla tego projektu. Kompiluje się dobrze, zanim zacząłem używać maven, być może maven dodał niepotrzebne zależności. Sprawdzę dwukrotnie.
— Edison

5
Mówiąc dokładniej, na plik wykonywalny (dex) Dalvik może istnieć tylko 65 536 metod. Aplikacja (APK) może mieć więcej niż jeden plik dex z takimi funkcjami jak ładowanie niestandardowe.
— Dennis Sheil

7
To naprawdę krępujący błąd dla Androida! W każdym razie, w moim przypadku usunąłem Jar, który był w bibliotekach i nie był używany, a aplikacja skompilowana
— David

Czas posprzątać mój projekt: /
— Decoy

1
Szybkim rozwiązaniem byłoby użycie Proguard również w kompilacjach debugowania
— ale

12

Poniższy kod pomaga, jeśli używasz Gradle. Pozwala łatwo usunąć niepotrzebne usługi Google (zakładając, że ich używasz), aby wrócić poniżej progu 65 tys. Podziękowania dla tego postu: https://gist.github.com/dmarcato/d7c91b94214acd936e42

Edytuj 22.10.2014 : Odbyło się wiele interesujących dyskusji na temat wspomnianej powyżej treści. TLDR? Patrz na to: https://gist.github.com/Takhion/10a37046b9e6d259bb31

Wklej ten kod na dole pliku build.gradle i dostosuj listę usług Google, których nie potrzebujesz:

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

Kocham to! def potrzebne, ponieważ firmy takie jak Google wciąż pompują pakiety.
— Edison

1
Fajnie - wykonało to miejsce pracy. Bez kłopotów i bez obaw!
— slott,

Uwaga: to usunięte słoiki usług Google Play w moim zestawie SDK Androida w Android Studio! Zły pomysł, ponieważ powrót do oryginalnych słoików nie jest łatwy. Autor powinien zmodyfikować skrypt, aby zmienić słoiki w katalogu kompilacji.
— inder

@inder: Nie miałem tego problemu. Musiałem jednak robić to za cleankażdym razem, gdy analizowałem wykluczenia (korzystamy z analiz).
— JohnnyLambada

jak wykluczyć to z kompilacji wersji?
— user1324936,

6

Udostępniłem przykładowy projekt, który rozwiązał ten problem za pomocą skryptu kompilacji custom_rules.xml i kilku wierszy kodu.

Użyłem go w swoim własnym projekcie i działa bezbłędnie na urządzeniach 1M + (od Androida-8 do najnowszego Androida-19). Mam nadzieję, że to pomoże.

https://github.com/mmin18/Dex65536


1
Dzięki za skrypty. powinieneś uważać na ART. Urządzenie może konwertować tylko domyślny plik dex, a nie pliki dodatkowe. Preferowane powinny być rozwiązania Proguard.
— Edison

2
Gdy importuję projekty do środowiska Eclipse i uruchamiam, pojawia się błąd. „Nie można wykonać dex: metody o numerze innym niż [0, 0xffff]: 65536”. Czy możesz wyjaśnić wykorzystanie projektu
— Karacago

6

Napotkałem ten sam problem i rozwiązałem go, edytując mój plik build.gradle w sekcji zależności, usuwając:

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

I zastępując go:

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

Doskonały! Po prostu używam interfejsu API Dysku Google i to działa.
— vedavis

5

Spróbuj dodać poniższy kod w build.gradle, to zadziałało dla mnie -

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}

2

Idealnym rozwiązaniem byłoby współdziałanie z Proguard. jak wspomniano w komentarzu aleb. Zmniejszy rozmiar pliku dex o połowę.


1
Zgoda, szczególnie ze słoikiem usług Google Play, szczególnie * (18k metod samodzielnie)
— Edison

2

Możesz przeanalizować problem (odwołania do plików dex) za pomocą Android Studio:

Kompilacja -> Analiza APK ..

W panelu wyników kliknij plik classes.dex

I zobaczysz:

wprowadź opis zdjęcia tutaj


0

rozwiązanie 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

Usuń plik jar z folderu Libs i skopiuj do innego folderu, a następnie przejdź do _ Właściwości projektu> Wybierz ścieżkę kompilacji Java, wybierz biblioteki, wybierz dodaj zewnętrzny jar, wybierz usunięty jar do swojego projektu, kliknij przycisk Zapisz, zostanie on dodany pod odnośnikiem Biblioteka zamiast folderu Libs. Teraz wyczyść i uruchom swój projekt. Nie musisz dodawać żadnego kodu dla MultDex. To po prostu działało dla mnie.


0

Dzisiaj miałem do czynienia z tą samą kwestią, która działała poniżej

Dla ANDROID STUDIO ... Włącz natychmiastowe uruchamianie

W Plik-> Preferencje-> Kompilacja, wykonanie, wdrożenie-> Natychmiastowe uruchomienie-> Zaznacz Włącz natychmiastowe uruchomienie dla Hot Swap ...

Mam nadzieję, że to pomoże


1
To zadziałało dla mnie - po prostu wyłączyłem opcję Włącz, kliknąłem Zastosuj, ponownie włączyłem i znów działało.
— MrBigglesworth
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.