Android Proguard优化设置:在现代API和Proguard版本中启用类合并、强制转换和字段/*功能

Android Proguard优化设置:在现代API和Proguard版本中启用类合并、强制转换和字段/*功能,android,optimization,proguard,Android,Optimization,Proguard,很长一段时间以来,我一直在混淆我的应用程序,下面的设置就像是咒语一样,因为它们是谷歌的推荐 -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* 然而,前几天我错误地评论了这句话,应用程序构建正确,“显然”可以工作。我做了很多测试,没能让它崩溃 所以我想知道是否需要这些禁用的优化设置 从今天的Android SDK和最新的Proguard版本开始,我

很长一段时间以来,我一直在混淆我的应用程序,下面的设置就像是咒语一样,因为它们是谷歌的推荐

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
然而,前几天我错误地评论了这句话,应用程序构建正确,“显然”可以工作。我做了很多测试,没能让它崩溃

所以我想知道是否需要这些禁用的优化设置

  • 从今天的Android SDK和最新的Proguard版本开始,我只针对Android 4.0.3以后的设备(15),并使用Proguard 5.1
  • 对于不做异国情调的应用程序,以及具有正确编写的
    proguard.cfg
    指令以保留相关问题类等
这里关于这个问题的大多数答案都有相互矛盾的信息,并且都与非常旧的API版本有关

逐一:

!代码/简化/算术 我发现了一个讨论,他们说继安卓甜甜圈之后,SDK不需要
简化/arithmetric
。我假设,我可以安全地启用此优化

!类/合并/* 启用此优化后,proguard在我的项目中似乎做得很好:

[proguard]   Number of vertically merged classes:         296
[proguard]   Number of horizontally merged classes:       445
除了堆栈跟踪不正确之外,还有其他副作用吗?我的意思是,副作用与应用程序崩溃有关,而不是与调试问题有关。我发现了,但不能断定它是否安全

!字段/*和!代码/简化/转换
我阅读了ProGuard作者的回答,这些都是为了避免老版本的ProGuard出现bug。因此,在Proguard 5.1上激活它们安全吗?

一般建议:不能保证优化不会起作用,但总有风险。默认的Android proguard设置试图做的是提供一种将风险降至最低的配置,因此,对于您的特定情况,它们显得如此保守

启用这些优化只意味着,如果某个系统崩溃,您无法确定根本原因。一般来说,proguard步骤对于输出应该与输入相关的内容没有那么有力的保证,这是程序中不确定性的一个来源。代码中的微小更改可能会导致运行时行为发生显著不同的变化,并且在实际运行程序之前,不可能知道这一点,这取决于您的配置

总之,如果你能运行你的APK,并且一切正常,那么很好,这些优化对你来说是可行的。但是,他们不能保证会这样做

那么在Proguard[5.1]上激活它们安全吗

这是一个高风险的举动,我可以给你举个例子,说明它会导致问题

我们使用的是ProGuard 5.2.1,在重新启用
字段/*
优化时遇到了一个错误(更具体地说,
字段/删除/写入似乎是问题的根源)。我们的代码使用protobuf,启用该优化会导致ProGuard在第三次优化时失败,并显示以下消息:

Optimizing... Unexpected error while evaluating instruction: Class = [com/google/protobuf/FieldSet$1] Method = [()V] Instruction = [308] isub Exception = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue]) Unexpected error while performing partial evaluation: Class = [com/google/protobuf/FieldSet$1] Method = [()V] Exception = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue]) Warning: Exception while processing task java.io.IOException: java.lang.IllegalArgumentException: Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue] 优化。。。 评估指令时出现意外错误: Class=[com/google/protobuf/FieldSet$1] 方法=[()V] 指令=[308]isub 异常=[java.lang.IllegalArgumentException](值“com/google/protobuf/WireFormat$JavaType!”不是整数值[proguard.evaluation.Value.TypedReferenceValue]) 执行部分求值时出现意外错误: Class=[com/google/protobuf/FieldSet$1] 方法=[()V] 异常=[java.lang.IllegalArgumentException](值“com/google/protobuf/WireFormat$JavaType!”不是整数值[proguard.evaluation.Value.TypedReferenceValue]) 警告:处理任务时出现异常java.io.IOException:java.lang.IllegalArgumentException:Value“com/google/protobuf/WireFormat$JavaType!”不是整数值[proguard.evaluation.Value.TypedReferenceValue]
这意味着这些优化已经被禁用了这么多年,这意味着它们可能没有像其他优化那样得到很好的维护。幸运的是,这是在编译时发现的,但重新启用其中一些优化(例如,通过
类/merging/*
水平合并类)可能很容易在Android的某些版本/构建中破坏你的应用程序,而不会正确地向你的“开发者”报告(例如,它可能会使dexopts崩溃或无法完全安装,同时出现
VerifyError
).

我还发现扁平化包结构,将所有类放在一个包下-repackageclasses对我来说很好。你知道只允许在特定的包层次结构上进行垂直合并吗?没有答案。这真的很奇怪。我一直在想同样的问题。你找到什么了吗?你启用了吗生产上的那些优化?是的,我成功地启用了它们。特别是,类合并与5次或5次以上的优化过程相结合做得很好。请注意,
Class/Merging/horizontal
,如果您有任何
-dontwarn
,可能会导致验证错误,因为该引用可能会合并到您的类中。该问题由@kennytm,ca提出n使用
-keep、allowshrinking、allowobfusion@android.annotation.TargetApi类*
(例如,禁用一些目标版本中没有的类的全局优化)。当然,要使该规则起作用,所有此类类都需要使用
@TargetApi
进行注释。Re-protobuf:这应该在(这个答案特别指出了有问题的优化,这暗示了修复,所以-谢谢!)