切换到 Gradle:为啥我必须防止自定义视图被混淆?
Posted
技术标签:
【中文标题】切换到 Gradle:为啥我必须防止自定义视图被混淆?【英文标题】:Switching to Gradle: why do I have to keep custom views from being obfuscated?切换到 Gradle:为什么我必须防止自定义视图被混淆? 【发布时间】:2015-02-12 18:18:41 【问题描述】:我正在将一个项目从 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 时不必处理?
显示该错误的确切原因是什么? (按照第一个问题的答案)
回答
@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);
我发现文档在这方面有点含糊不清,我希望可以对其进行编辑以消除它可能存在的任何歧义。总而言之,我的错。
【问题讨论】:
如何/在哪里创建自定义视图? 必须保留构造函数,因为LayoutInflater
正在使用它们,但这不能仅从源的静态分析中推断出来。我想你真正的问题是为什么不使用曾经是 SDK 一部分的 ProGuard/DexGuard 默认配置?我的猜测是这是因为 Gradle 插件最近发生了变化,以及 runProguard
被重命名以及其他类似的东西。如果您使用 SDK 中的 ProGuard,请咨询 adt-dev Google 小组。如果您使用的是 DexGuard,请查看下载门户,最近有一些快速连续更新。
@Barend 我不确定why is the ProGuard/DexGuard default config that used to be part of the SDK not used
应该是什么意思。我想知道为什么 Ant 和 Gradle 有不同的行为,因为两者都使用相同版本的 DexGuard 并且都使用相同的配置文件。
@pskink 只是标准的自定义视图。我已经定义了所有可能的构造函数,它们只调用 super()。
@dextor 在$ANDROID_HOME/tools/proguard
中有一些随SDK 一起提供的默认配置,并且aapt
会即时生成一些额外的配置。一个或另一个可能不存在,但我不知道这一点,我只是在猜测。如果你在 Windows 上,它可能像“程序文件”中的空间一样愚蠢。
【参考方案1】:
很可能 Ant 使用了不同的配置文件,
对于 Gradle,您还需要明确声明您还想使用 Android proguard 配置文件,即使用多个规则文件,如下所示:
proguardFile getDefaultProguardFile('proguard-android.txt')
proguardFile 'your/sepcific/folder/proguard.cfg'
(我记得 Ant 从来没有使用过 SDK proguard 文件,以前建议复制所有配置)。
【讨论】:
不,我(仍然)使用相同的配置文件。现在唯一的区别是保留自定义视图。另外,我仔细检查了我的 build.gradle,它正确指向了我的配置文件(否则,其他东西也会停止工作)。 我用你的答案和这种行为的原因更新了 OP。以上是关于切换到 Gradle:为啥我必须防止自定义视图被混淆?的主要内容,如果未能解决你的问题,请参考以下文章
我可以将 UITapGestureRecognizer 添加到我的控制器 self.view,但不能添加到任何自定义视图。为啥?