NoClassDefFoundError: android.support.v7.internal.view.menu.MenuBuilder 类未找到错误:android.support.v7.internal.view.menu.MenuBuilder

170

在运行 Android 4.2 的三星设备上,Android appcompat v7 库存在问题。我在开发者控制台中看到以下堆栈跟踪信息,应用程序一直崩溃:

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)

这是CustomActivity.java的第215行:

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

崩溃是由一系列设备引起的,但总是三星,而且总是Android 4.2。

快速的网络搜索让我相信很多人都有同样的问题,我试图尝试以下一些步骤来解决这个问题:

  • 检查Android项目属性,确保已正确添加appcompat库。
  • 检查Java Build Path Order和Export项目属性,确保已选中Android依赖项和Android私有库。
  • 确认该类包含在库中(android.support.v7.internal.view.menu.MenuBuilder)。
  • 确认R.java位于android.support.v7.appcompat的gen目录中。
  • 确认AppCompat主题已包含在Manifest.xml活动中。
  • 清理并重新构建项目。

尽管尝试了这些步骤,而且它在所有其他设备和Android版本上都能工作,但崩溃报告仍然持续产生。


4
注意:我也在一款叫做 QMobile X25 的低端手机上看到了这种情况,该手机产自巴基斯坦。因此看起来其他人采取了与失败的三星ROM相同的方法或相同的ROM。 - William
由于谷歌和三星都没有帮助解决这个巨大的问题,有没有人能想到一个不涉及Proguard(会引发其他问题)的解决方案? - checklist
谷歌不会采取任何行动,因为似乎是三星进行了额外的修改,导致库之间发生名称冲突。Proguard避免了这种冲突。在Android问题跟踪器论坛上也没有看到更好的解决方案。 - Matt K
我也可以添加来自巴基斯坦以外的QMobile A290。 - sstn
2
同样问题 [QMobile X30 - Android 4.4.2] - shanraisshan
10个回答

100

编辑:

对我起作用的解决方案是(使用Proguard)将以下内容替换为:

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

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

用这个:

# 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.** {*;}

感谢Google Group #138提供的帮助。

旧答案(临时解决方案): 在我使用ActionBar中的下拉菜单的项目中出现了这个问题。我的解决方案是检查这些条件并更改应用程序流程:

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");
}

然后在活动的onCreate方法中:

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

正如所指出的,这并不是一个明确的解决方案,而是一种让用户在寻找更加永久性的解决方案时获得有限功能的方法。


3
@JaredBurrows,你不需要移除这个库,只需告诉Proguard默认忽略它,使用修复程序时,忽略android.support下的所有内容,但保留android.support.v7.internal.view.menu。 - unify
2
我已经使用那个问题报告中的解决方案好几个月了,但突然在更新到最新的支持库和sdk 23之后,我开始在crashlytics上收到这个新的报告:java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.i - casolorz
3
当我升级到AppCompat v23版本后,我的应用程序出现了问题。我分析了AppCompat v.23.1.1 jar文件,并发现它们已经删除了v7内部目录,因此似乎Proguard指令行现在应该是:[-keep class !android.support.v7.view.menu.,android.support. {*;}]我仍然没有在实际设备上测试确认该问题是否已解决。有没有人能够使用这样的设备进行测试?或者也许删除'internal'目录实际上就是解决问题的方法,我们不需要再去处理Proguard类重命名了? - gregko
7
将以下内容添加到您的proguard设置中,它将解决问题:对于APPCOMPAT 23.1.1:-keep class !android.support.v7.view.menu.MenuBuilder, android.support.v7.** { ; } -keep interface android.support.v7.* { *; }对于旧版本的APPCOMPAT:-keep class !android.support.v7.internal.view.menu.MenuBuilder, android.support.v7.** { ; } -keep interface android.support.v7.* { *; } - Andrea Bellitto
2
我们的测试证实,根本问题已在支持库24.0.0中得到解决。(官方发布版,而非仅仅是alpha版。)我们升级到了24.0.0,移除了ProGuard混淆的解决方法,在之前出现崩溃的三星设备上进行了测试,现在不再出现该问题。 - Mark McClelland
显示剩余25条评论

26

#150 from google groups所述:

请小心使用-keep class !android.support.v7.internal.view.menu.**。里面有许多从appcompat的资源中引用的类。

更好的解决方案是添加以下几行代码:

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

在我的测试中,基于生成的Proguard映射文件的审查,这个建议的Proguard配置没有导致MenuBuilder类名被混淆,虽然它确实混淆了SubMenuBuilder。 - Andy Dennie
3
有人删除了它,不知道为什么。无论如何,这是我的解决方案: -keep class !android.support.v7.internal.view.menu.* implements android.support.v4.internal.view.SupportMenu, android.support.v7.** {*;} - Andy Dennie
3
在使用v23版本的app compat时,-keep class !android.support.v7.internal.view.menu.**,** {*;}已经不再起作用,但对我来说这个做法有效。 - Quentin Klein
1
-keep class !android.support.v7.internal.view.menu.MenuBuilder, android.support.v7.** { ; } -keep interface android.support.v7.* { *; } - Quentin Klein
2
在23.1.1支持库中,内部包路径已被修改,因此正确的proguard设置如下:-keep class !android.support.v7.view.menu.MenuBuilder, android.support.v7.** { ; } -keep interface android.support.v7.* { *; } - Andrea Bellitto
显示剩余9条评论

23

您使用哪种设备遇到了这个问题?(三星/HTC等)

如果是三星:

各种三星手机在框架或类路径中都包含旧版本的安卓支持库。如果您使用新的材料支持库,则会在这些三星设备上看到此崩溃:

java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.MenuBuilder
要解决这个问题,您需要重新命名那个类。最简单的方法是运行proguard。如果您不想混淆,请使用以下一行代码仅重命名有问题的类:

要解决此问题,您必须更改该类的名称。最简单的方法是运行 ProGuard。如果您不想进行混淆,可以使用以下一行代码仅重命名有问题的类:

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

有一个问题追踪这个问题,但由于它实际上是三星的一个错误,他们永远不会在他们的端解决它。唯一的解决办法是在Google / AOSP方面将这些内部类重命名。

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


2
@Android007:感谢您指出这个实际有效的解决方法。然而,似乎没有人能够解释为什么在引导类路径中嵌入旧版Android支持库的错误ROM会导致此异常,因为缺少的“android.support.v7.internal.view.menu.MenuBuilder”类在遭受此问题的应用程序的.apk DEX代码中是可用的。如果您手头有任何指针可以解释Android运行时如何加载来自引导类路径jar/dex文件和应用程序的类,或者有任何精确的解释,请告诉我。 - Édouard Mercier
1
谢谢@Android007,作为任何一名程序员,我都不太喜欢巫术 ;) 一个提示:嵌入式bootclasspath是否包含"sealed" .jar/.dex,这可能会解释其行为? - Édouard Mercier
如果与默认的Java类加载器相同,则始终将委派加载给根类加载器。因此,如果这些设备将这些库的旧版本添加到bootclassloader中,它们将首先被看到。也就是说,它们正在为APK遮蔽类。@ÉdouardMercier - William
1
@Android007的答案提供的解决方案是我找到的最好的一个。其他的解决方案会导致奇怪的问题,阻止应用程序的构建。 - Dick Lucas
有人知道安装更新的支持库是否可以修复这个 bug 吗? - TheLettuceMaster
显示剩余4条评论

15

这个问题出现在AppCompat 23.1.1中,其中.internal包已从库jar中删除。

如上面的评论所建议(感谢提供建议的人),现在还必须更改proguard配置。

为了让上述建议的答案再次起作用,请尝试将这些行添加到您的proguard文件中:

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

改为以下修正:

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

!android.support.v7.view.menu.**更安全,因为还有其他类,如SubMenuBuilder。 - JaredBanyard

12

我们的测试证实24.0.0版本修复了该问题。我们升级了支持库至24.0.0(非alpha版),移除了我们之前使用的混淆解决方法,并在三星测试设备上未发现之前出现的崩溃情况。 - Mark McClelland

4

我也遇到了在USB调试模式下找不到MenuBuilder类的问题。我通过在build.gradle文件中将minifyEnabled设置为true,并在release和debug的buildTypes块中都进行设置来解决这个问题。示例如下:

buildTypes {

    debug {

        minifyEnabled true
    }

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

我将minifyEnabled设置为true,在debug类型中,以防止通过USB调试连接到实时手持设备时应用程序崩溃。


4

是的。三星已经知道了这个this问题。 我建议你尝试使用来自GitHub的相同弹出窗口实现。这不是最好的方法,但会起作用。


1
是的,我在三星论坛上看到了这个问题,但似乎他们并不感兴趣,因为他们的代表或支持人员都没有回复。 - Matt K

0

我在Eclipse项目中使用默认的Proguard属性启用了Proguard,这解决了我的问题。根据这里的一些评论 https://code.google.com/p/android/issues/detail?id=78377 ,有些人可能需要使用以下命令重新打包: -repackageclasses "android.support.v7"


似乎大多数论坛用户都无法使用。回退到Appcompat-20似乎是更可靠的选择。 - Matt K
这个问题据说已经在支持v23.1.1中得到解决。 - Tim Malseed

0

当我尝试通过Android Studio在我的三星Galaxy Tab 3平板电脑上运行“Hello World”应用程序时,我遇到了相同的错误。应用程序似乎会启动,然后立即崩溃,并且该错误将显示在Android Studio中的控制台中。我在平板电脑上进行了系统更新,现在我能够运行“Hello World”应用程序,不再出现错误了。我希望这可以帮助某人解决他们的问题。

注意:我在平板电脑上执行的系统更新没有更新Android OS版本,因为仍然显示版本为4.2.2。


-4

将您的项目的编译SDK版本更改为"API 18:(果冻豆)"

默认设置为"棒棒糖"

步骤

  1. 右键单击您的项目,选择打开模块设置(或按F4)
  2. 在属性选项卡中编译SDK版本

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接