【问题标题】:Gradle release build with proguard: java.lang.IncompatibleClassChangeError and java.lang.NoSuchMethodError使用 proguard 构建 Gradle 版本:java.lang.IncompatibleClassChangeError 和 java.lang.NoSuchMethodError
【发布时间】:2014-03-13 23:47:30
【问题描述】:

我最近将一个项目从 Eclipse/Ant 迁移到 Android Studio/Gradle。我能够在启用 proguard 的情况下成功构建项目的签名发布版本。但是,在测试发布版本时,我遇到了某些库项目和 jar 的崩溃(在构建调试版本时可以正常工作)。

例如,当尝试将文件上传到 Dropbox(一个 jar 依赖项)时,我收到以下错误:

java.lang.IncompatibleClassChangeError: interface not implemented
   at com.dropbox.client2.session.AbstractSession.sign(SourceFile:238)
   at com.dropbox.client2.DropboxAPI.putFileRequest(SourceFile:2199)
   at com.dropbox.client2.DropboxAPI.putFileOverwriteRequest(SourceFile:1571)
   at com.dropbox.client2.DropboxAPI.putFileOverwrite(SourceFile:1537)

另外,在尝试登录 Box(库项目依赖项)时,我收到以下错误:

java.lang.NoSuchMethodError: org.apache.http.conn.params.ConnManagerParams.setMaxTotalConnections
   at com.box.restclientv2.BoxBasicRestClient.()
   at com.box.boxjavalibv2.BoxRESTClient.()
   at com.box.boxjavalibv2.BoxClient.createRestClient()
   at com.box.boxjavalibv2.BoxClient.()
   at com.box.boxandroidlibv2.BoxAndroidClient.(SourceFile:49)
   at com.box.boxandroidlibv2.activities.OAuthActivity.startOAuth(SourceFile:71)
   at com.box.boxandroidlibv2.activities.OAuthActivity.onCreate(SourceFile:52)

我还有其他运行良好的 jar 和库项目...

同样,在构建 gradle 调试版本(无 proguard)时,这些都没有问题。我还能够使用 ant 创建一个启用了 proguard 的发布版本,没有任何问题(能够登录 Dropbox 和 Box)。

有什么想法吗?

【问题讨论】:

  • 看来添加 proguard 规则 -keep class org.apache.http.** { *; } 已经“修复”了这两个崩溃。我对此还是有点不自在,因为当我用 Ant 构建项目时,不需要这个 proguard 规则。这条规则确实有道理,为什么它修复了 Box 崩溃的 NoSuchMethodError,而不是 Dropbox 崩溃。谁能解释一下?

标签: android proguard dropbox-api box-api android-gradle-plugin


【解决方案1】:

您似乎包含了 org.apache.http 库的一个版本。原则上,这个库已经是 Android 运行时 android.jar 的一部分,所以你不应该将它添加到你的项目中。 ProGuard 可能正在打印有关这些重复类的警告。

实际上,它可能是该库的较新版本,并且您的某些代码可能正在使用此版本中的其他类。然后,您可能应该保持类、字段和方法的名称不变,以避免引入(额外的)冲突:

-keep class org.apache.http.** { *; }

构建过程可能会过滤掉类,或者它可能会添加上面的行,但我认为默认的 Android 构建当前也不会这样做。

【讨论】:

    【解决方案2】:

    您需要-keep Proguard 删除或重命名它无法确定的所有类和方法名称,这些名称是从它不处理的代码中引用的,通过反射引用的(例如 XML 引用)等。

    保留所有 apache 类可能会超出必要(这是可以的),但可能不足以解决所有 Proguard 问题。

    很高兴问一下为什么没有这个-keep,它在你的 ant 构建中也能正常工作。也许 ant 构建实际上并没有调用 Proguard(ant 很棘手),也许它使用了不同的 Proguard 数据文件,或者相关库在此期间发生了变化。您可以通过列出假设并对其进行测试来进行调试。例如。如果你在 Proguard 数据文件中放了一个格式错误的命令然后运行 ​​ant 构建,你可以判断它是否真的运行 Proguard。

    【讨论】:

    • 比较构建是个好主意。你可以让 ProGuard 写出它与-printconfiguration conf.txt 一起使用的配置。这将包括输入 jar 和库 jar。
    • Jerry101,我了解 proguard 的工作原理,并且我很肯定 proguard 正在我的 ant 构建上运行(我有很多缺失的 proguard 规则,我过去不得不寻找) . @EricLafortune 谢谢。我会看看我是否可以比较配置。我仍然认为新的 Android gradle 构建系统有些可疑。似乎它没有“保护”Android SDK 的部分免受 proguard (例如 org.apache.http 包)的影响。我在这里提交了一个错误报告:code.google.com/p/android/issues/detail?id=67166
    • 很高兴你正在调试这个并提交了一个错误。更多调试思路:创建一个最小的测试项目,调用 apache.http 重现问题。使用 Proguard 设置 printconfiguration、dump 和 verbose 来查看它在做什么以及它使用的确切配置。将实际配置与 ant build 进行比较。由于典型的 gradle 构建使用标准的 proguard 配置文件 + 项目特定的配置文件,问题可能出在前者,尽管如果这个库在操作系统中而不是包含在 APK 中,它仍然很可疑。
    猜你喜欢
    • 2014-08-29
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多