12

我正在将一个项目从 Ant 转移到 Gradle,但有些事情我就是想不通。


事实

在构建了一个发布 APK(即混淆)后,我注意到应用程序严重崩溃了。错误可以总结为:

java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]

调试(即非混淆)APK 工作得很好,所以我猜它与我的 ProGuard/DexGuard 配置有关。

我试图通过添加以下语句来保留类引用:

-keep class com.mypackage.MyCustomView

因此,发布 APK 工作得很好。然后我做了一些研究,并尝试了这个更具体的 ProGuard/DexGuard 配置:

-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

这也有效,并且与类无关


问题

我想知道:

  1. 为什么我在使用 Ant 时不必处理 is?
  2. 出现该错误的确切原因是什么?(按照第一个问题的答案)

回答

@Blundell 的回答基本上是正确的。原来我在build.gradle配置中遗漏了一行:

android {
  ...
  buildTypes {
    debug {
      ...
    }
    release {
        proguardFile getDefaultDexGuardFile('dexguard-release.pro') # <----- this line
        proguardFile 'dexguard-project.txt'
    }
  }
}

看来该行实际上是强制性的,因为它是ProGuard/DexGuard的基本规则集。事实上,这是dexguard-release.pro文件的一部分:

-keepclassmembers !abstract class !com.google.ads.** extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

-keepclassmembers !abstract class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * extends android.content.Context {
   public void *(android.view.View);
}

我发现文档在这方面有点含糊不清,我希望可以对其进行编辑以消除它可能存在的任何歧义。总而言之,我的错。

4

1 回答 1

4

很可能 Ant 使用了不同的配置文件,

同样使用 Gradle,您需要明确声明您还想使用 Android proguard 配置文件,即使用多个规则文件,如下所示:

    proguardFile getDefaultProguardFile('proguard-android.txt')
    proguardFile 'your/sepcific/folder/proguard.cfg'

(我记得 Ant 从未使用过 SDK proguard 文件,并且曾经建议复制所有配置)。

于 2014-12-15T11:58:35.307 回答