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

Edison
źródło
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.

Alex Lipov
źródło
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

Patrick Favre
źródło
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

blobbie
źródło
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
    }
}
mcm
źródło
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

min
źródło
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' 
Luis Miguel Ballestas
źródło
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
}
Sunita
źródło
2

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

shimi_tap
źródło
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

alexshr
źródło
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/**'
            }
        }
    }
  }
}
Oleg Khalidov
źródło
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.

Lakszmanan
źródło
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

Abdul Waheed
źródło
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