我正在将一个项目从 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);
}
这也有效,并且与类无关。
问题
我想知道:
- 为什么我在使用 Ant 时不必处理 is?
- 出现该错误的确切原因是什么?(按照第一个问题的答案)
回答
@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);
}
我发现文档在这方面有点含糊不清,我希望可以对其进行编辑以消除它可能存在的任何歧义。总而言之,我的错。