NoClassDefFoundError: android.support.v7.internal.view.menu.MenuBuilder

170

Występuje problem z biblioteką Android appcompat v7 na urządzeniach Samsung z systemem Android 4.2. W mojej Konsoli programisty ciągle pojawiają się awarie z następującym śladem stosu:

java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.MenuBuilder
    at android.support.v7.widget.PopupMenu.<init>(PopupMenu.java:66)
    at com.[my-package-name].CustomActivity$5.onClick(CustomActivity.java:215)
    at android.view.View.performClick(View.java:4222)
    at android.view.View$PerformClick.run(View.java:17620)
    at android.os.Handler.handleCallback(Handler.java:800)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:194)
    at android.app.ActivityThread.main(ActivityThread.java:5391)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
    at dalvik.system.NativeStart.main(Native Method)

To jest wiersz 215 pliku CustomActivity.java:

PopupMenu popup = new PopupMenu(CustomActivity.this, mImageViewMenu);

Awarie pochodzą z szeregu urządzeń, ale zawsze Samsung i zawsze Android 4.2.

Szybkie wyszukiwanie w Internecie prowadzi mnie do wniosku, że wiele osób ma ten sam problem, niektóre z kroków, które próbowałem rozwiązać, to:

  • Sprawdź właściwości projektu Android, upewnij się, że biblioteka appcompat została poprawnie dodana.
  • Sprawdź kolejność ścieżek budowania języka Java i właściwości eksportu projektu, upewnij się, że zaznaczone są zależności systemu Android i biblioteki prywatne systemu Android.
  • Upewnij się, że klasa znajduje się w bibliotece (android.support.v7.internal.view.menu.MenuBuilder).
  • Sprawdź, czy R.java znajduje się w katalogu gen dla android.support.v7.appcompat.
  • Sprawdź, czy motyw AppCompat jest uwzględniony w działaniu Manifest.xml.
  • Wyczyść i przebuduj projekt.

Pomimo tych kroków i pomimo tego, że działa na wszystkich innych urządzeniach i wersjach Androida, raporty o awariach wciąż przychodzą.

Matt K.
źródło
4
Uwaga: widziałem to również na QMobile X25, który jest telefonem z niższej półki z Pakistanu. Wygląda więc na to, że inni mają to samo podejście lub tę samą pamięć ROM, co uszkodzony ROM Samsunga.
William
Ponieważ zarówno Google, jak i Samsung nie są pomocne w rozwiązaniu tego OGROMNEGO problemu, czy ktoś może wymyślić rozwiązanie, które nie obejmuje Proguard (co powoduje inne problemy)?
lista kontrolna
Google nic z tym nie zrobi, ponieważ wydaje się, że to Samsung wprowadził dodatkowe modyfikacje powodujące kolizję nazw między bibliotekami. Proguard unika kolizji. Nie widziałem też lepszych rozwiązań na forum Android Issue Tracker .
Matt K
Mogę dodać QMobile A290, także poza Pakistanem.
sstn
2
ten sam problem [QMobile X30 - Android 4.4.2]
shanraisshan

Odpowiedzi:

100

EDYTOWAĆ:

Rozwiązaniem, które działało dla mnie, było (Korzystanie z Proguard), aby zastąpić to:

-keep class android.support.v4.** { *; } 
-keep interface android.support.v4.** { *; }

-keep class android.support.v7.** { *; }
-keep interface android.support.v7.** { *; }

z tym:

# Allow obfuscation of android.support.v7.internal.view.menu.**
# to avoid problem on Samsung 4.2.2 devices with appcompat v21
# see https://code.google.com/p/android/issues/detail?id=78377
-keep class !android.support.v7.internal.view.menu.**,android.support.** {*;}

Kredyt trafia do grupy Google, nr 138 .

Stara odpowiedź (tymczasowe obejście): Dzieje się tak w projekcie, w którym używam pokrętła w ActionBar. Moim rozwiązaniem było sprawdzenie tych warunków i zmiana przepływu aplikacji:

public static boolean isSamsung_4_2_2() {
    String deviceMan = Build.MANUFACTURER;
    String deviceRel = Build.VERSION.RELEASE;
    return "samsung".equalsIgnoreCase(deviceMan) && deviceRel.startsWith("4.2.2");
}

Następnie w metodzie onCreate działania:

if (isSamsung_4_2_2()) {
    setContentView(R.layout.activity_main_no_toolbar);
} else {
    setContentView(R.layout.activity_main);
}

Jak wskazano, nie jest to ostateczne rozwiązanie, jest to po prostu sposób, aby umożliwić użytkownikom dostęp do ograniczonej funkcjonalności, podczas gdy zostanie znalezione bardziej trwałe rozwiązanie.

ujednolicić
źródło
2
Czy ktoś może zweryfikować tę odpowiedź? Nie mam dostępu do Samsunga, a aplikacja, nad którą pracowałem, nie jest już aktywna, więc nie mogę jej przetestować.
Matt K
3
@JaredBurrows Nie usuwasz biblioteki, po prostu mów proguardowi, aby ją domyślnie ignorował, z poprawką ignorujesz wszystko w android.support z wyjątkiem android.support.v7.internal.view.menu
unify
2
Od miesięcy korzystam z rozwiązania z tego raportu problemu i nagle po aktualizacji do najnowszych bibliotek wsparcia i sdk 23 Zacząłem otrzymywać ten nowy raport o crashlytics:java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.i
casolorz
3
Problem powrócił w mojej aplikacji po uaktualnieniu II do AppCompat v23. Przeanalizowałem plik jar AppCompat v.23.1.1 i stwierdziłem, że usunęli oni „wewnętrzny” katalog w wersji 7, więc wygląda na to, że wiersz instrukcji Proguard powinien być teraz: [-keep class! Android.support.v7.view. menu. **, android.support. ** {*;}] Nadal nie mam potwierdzenia z testów na prawdziwym urządzeniu, na którym wystąpił problem. Czy ktoś z takim urządzeniem mógłby to przetestować? A może usunięcie katalogu „wewnętrznego” jest w rzeczywistości rozwiązaniem problemu i nie musimy już mieszać przy zmianie nazwy klasy Proguard?
gregko
7
Dodaj to do ustawień proguard, to rozwiąże problem: DLA APPCOMPAT 23.1.1: -keep class! Android.support.v7.view.menu. * MenuBuilder *, android.support.v7. ** { ; } -keep interface android.support.v7. * { ; } DLA STARSZEJ WERSJI APPCOMPAT: -keep class! Android.support.v7.internal.view.menu. * MenuBuilder , android.support.v7. ** { ; } -keep interface android.support.v7. * {*; }
Andrea Bellitto
26

Jako nr 150 z grup google powiedział

Ponieważ uważaj na -keep class! Android.support.v7.internal.view.menu. **. Istnieje tam wiele klas, do których istnieją odwołania z zasobów appcompat.

Lepszym rozwiązaniem jest dodanie następujących linii:

-keep class !android.support.v7.internal.view.menu.*MenuBuilder*, android.support.v7.** { *; }
-keep interface android.support.v7.** { *; }
Pongpat
źródło
W moich testach, opartych na przeglądzie wygenerowanego pliku mapowania proguard, ta sugerowana konfiguracja proguard nie powoduje zaciemnienia nazwy klasy MenuBuilder, chociaż zaciemnia SubMenuBuilder.
Andy Dennie
3
@William Ktoś go usunął, nie wiem dlaczego. W każdym razie, oto moje rozwiązanie: -keep class !android.support.v7.internal.view.menu.* implements android.support.v4.internal.view.SupportMenu, android.support.v7.** {*;}
Andy Dennie
3
To zadziałało dla mnie tam, gdzie -keep class !android.support.v7.internal.view.menu.**,** {*;} nie działało już z v23 z aplikacjami COMPAT .
Quentin Klein
1
-keep class !android.support.v7.internal.view.menu.*MenuBuilder*, android.support.v7.** { *; } -keep interface android.support.v7.** { *; } jako odpowiedź :)
Quentin Klein
2
w bibliotece obsługi 23.1.1 wewnętrzne ścieżki pakietów zostały zmodyfikowane, więc teraz prawidłowe ustawienie proguard to: -keep class! android.support.v7.view.menu. * MenuBuilder *, android.support.v7. ** { ; } -keep interface android.support.v7. * {*; }
Andrea Bellitto
23

Na jakim urządzeniu masz do czynienia z tym problemem? (Samsung / HTC itp.)

Jeśli to Samsung,

Różne telefony Samsung są dołączone do starszych wersji biblioteki obsługi systemu Android w ramach lub ścieżce klas. Jeśli korzystasz z nowej biblioteki obsługi materiałów, zobaczysz tę awarię na tych urządzeniach Samsung:

java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.MenuBuilder

Aby to naprawić, musisz zmienić nazwę tej klasy. Najłatwiej to zrobić, uruchamiając program proguard. Jeśli nie chcesz zaciemniać treści, oto 1 linijka do zmiany nazw tylko naruszających klas:

-keep class !android.support.v7.internal.view.menu.**,** {*;}

Występuje problem ze śledzeniem tego problemu, ale ponieważ jest to naprawdę błąd Samsunga, nigdy nie zostanie on naprawiony. Jedynym sposobem na naprawienie tego po stronie Google / AOSP jest zmiana nazw tych klas wewnętrznych.

https://code.google.com/p/android/issues/detail?id=78377

Ganesh AB - Android
źródło
Czy używasz programu Proguard do obsługi wersji 4?
Jared Burrows
@JaredBurrows Próbowałem wsparcia v7. Ale dla v4 też będzie działać.
Ganesh AB - Android
2
@ Android007: dziękujemy za wskazanie obejścia, które faktycznie działa. Jednak wydaje się, że nikt nie jest w stanie wyjaśnić, dlaczego wadliwe ROM-y osadzające starą bibliotekę obsługi Androida w ścieżce bootclasspath powodują ten wyjątek, ponieważ brakująca klasa „android.support.v7.internal.view.menu.MenuBuilder” jest dostępna w. apk Kod DEX aplikacji, której dotyczy ten problem. Czy miałbyś pod ręką jakiś wskaźnik, który wyjaśnia, w jaki sposób środowisko wykonawcze Androida ładuje klasy pobrane z plików jar / dex ścieżki bootclasspath i aplikacji? Albo jakieś dokładne wyjaśnienie?
Édouard Mercier
@ ÉdouardMercier Przepraszamy za spóźnioną odpowiedź. Obecnie nie mam odpowiedzi na Twoje pytanie, ale wkrótce skontaktuję się z Tobą. :)
Ganesh AB - Android
Dziękuję @ Android007, jak każdy programista, nie lubię zbytnio czarów;) Jedna wskazówka: czy osadzona ścieżka bootclas zawierałaby "zapieczętowane" pliki .jar / .dex, co tłumaczyłoby to zachowanie?
Édouard Mercier
15

Ten problem powrócił AppCompat 23.1.1tam, gdzie.internal pakiet został usunięty z biblioteki jar.

Jak zasugerowano w komentarzach powyżej (podziękowania dla osób, które to zasugerowały), teraz również konfiguracja proguard musi się zmienić.

Aby odpowiedź sugerowana powyżej działała ponownie, spróbuj dodać te wiersze do plików proguard:

#FOR APPCOMPAT 23.1.1:
-keep class !android.support.v7.view.menu.*MenuBuilder*, android.support.v7.** { *; }
-keep interface android.support.v7.* { *; }

Zamiast starej poprawki:

#FOR OLDER APPCOMPAT VERSION:
-keep class !android.support.v7.internal.view.menu.*MenuBuilder, android.support.v7.** { ; }
-keep interface android.support.v7.* { *; }
RWIL
źródło
!android.support.v7.view.menu.**jest bezpieczniejszy dzięki innym klasom, takim jak SubMenuBuilder
JaredBanyard
12

Zgodnie z ostatnimi postami raportu o błędzie, powinno to zostać naprawione w nowej wersji biblioteki wsparcia (24.0.0): https://code.google.com/p/android/issues/detail?id=78377 # c374

Ktoś nawet twierdził , że to naprawił.

Ta wersja jest dostępna od zeszłego miesiąca , więc powinieneś ją zaktualizować.

programista Androida
źródło
Nasze testy potwierdzają, że wersja 24.0.0 rozwiązuje problem. Zaktualizowaliśmy bibliotekę wsparcia do 24.0.0 (nie alfa), usunęliśmy zaciemnianie, którego używaliśmy jako obejścia, i nie widzieliśmy żadnych awarii na urządzeniu testowym Samsung, na którym wcześniej widzieliśmy awarię.
Mark McClelland
4

Tak. Samsung już wie o tym problemie. Mogę zasugerować, abyś spróbował użyć tej samej implementacji Popup z GitHub . To nie jest najlepszy sposób, ale będzie działać.

Eldar Miensutov
źródło
1
Tak, widziałem to na forum Samsunga, ale nie wygląda na to, że są zainteresowani, ponieważ żaden z ich przedstawicieli ani wsparcia nie odpowiedział.
Matt K,
4

Miałem ten sam problem z tą klasą MenuBuilder, która nie została znaleziona w trybie debugowania USB. Rozwiązałem ten problem, po prostu ustawiając minifyEnabled na wartość true zarówno w bloku buildTypes wydania, jak i debugowania build.gradle . lubię to:

buildTypes {

    debug {

        minifyEnabled true
    }

    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

Ustawić minifyEnabled true w debugowania typu, aby zapobiec awariom poprzez aplikację debugowania USB na żywo słuchawce.

FAQi
źródło
0

Włączyłem proguard z domyślnymi właściwościami proguard dostarczonymi z projektem zaćmienia i problem został rozwiązany dla mnie. Opierając się na komentarzach tutaj https://code.google.com/p/android/issues/detail?id=78377 , niektóre osoby mogą być zmuszone do przepakowania za pomocą: -repackageclasses "android.support.v7"

u2tall
źródło
Wygląda na to, że to nie działa dla większości ludzi na forum. Wygląda na to, że powrót do appcompat-20 jest bardziej niezawodną opcją.
Matt K
Przypuszczalnie zostało to rozwiązane w obsłudze wersji 23.1.1
Tim Malseed,
0

Ten sam błąd wystąpił podczas próby uruchomienia aplikacji „Hello World” na moim tablecie Samsung Galaxy Tab 3 przez Android Studio. Wyglądało na to, że aplikacja uruchamia się, a następnie natychmiast ulegała awarii, a ten błąd był wyświetlany w konsoli w Android Studio. Zrobiłem aktualizację systemu na tablecie i teraz mogę uruchomić aplikację „Hello World” i już nie otrzymuję błędu. Mam nadzieję, że pomoże to komuś rozwiązać problem.

Uwaga: aktualizacja systemu, którą przeprowadziłem na tablecie, nie zaktualizowała wersji systemu operacyjnego Android, ponieważ nadal mówi, że jest to wersja 4.2.2.

JulianDavid
źródło
-4

Zmień wersję kompilacji Sdk projektu na „API 18: (JellyBean)”

Domyślnym ustawieniem jest „Lollipop

KROKI

  1. Kliknij prawym przyciskiem myszy swój projekt i wybierz Otwórz ustawienia modułu (lub naciśnij F4)
  2. Na karcie właściwości Skompilowana wersja Sdk
Jazib Hasan
źródło