【问题标题】:Android ProGuard: Most Aggressive OptimizationsAndroid ProGuard:最激进的优化
【发布时间】:2016-05-21 04:34:52
【问题描述】:

Android 官方proguard documentation 展示了两个主要优化:

  • minifyEnabled设置为true
  • 使用proguard-android-optimize.txt 而不是proguard-android.txt

这两个可能是最激进的设置吗?

我正在编写一个 android 库,需要确保当人们使用我的库时我的代码不会中断。 (我知道我可以在我的库中放置一些规则来对抗使用该库的应用程序上设置的 proguard 配置,但如果我不需要,我不想这样做。)

【问题讨论】:

  • 你要在 jcenter 上传你的库吗?因为我认为 ProGuard 不会在这种情况下产生影响。您可能会看看一些已经运行良好的库 - Material Dialogs。或者直接查看android-arsenal.com
  • 我希望每个图书馆作者都非常关心 ProGuard。通常情况下,我们需要自己弄清楚第三方库的 ProGuard 规则。
  • 我很好奇你预期会从这个问题中得到什么。外部资源?推荐?从技术上讲,您的问题可以用“是”或“否”来回答,但我怀疑您正在寻找更多?
  • 我希望 1. 是的,这就是它可以进一步优化的方法或 2. 不,这是一个关于为什么不这样做的合乎逻辑的证据,或者一个可靠的消息来源说它不能。

标签: android optimization proguard


【解决方案1】:

请记住,最好的 ProGuard 配置 - 是具有最少异常的配置。 在我理解的例外情况下:

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

让我们浏览一下 proguard-android-optimize.txt 并查看优化/混淆选项。

有关 ProGuard 选项的详细说明,我使用 this

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* This - 可能的优化列表,!表示否定,所以不使用这个优化

-optimizationpasses 5 指定要执行的优化遍数。默认情况下,执行单遍。多次通过可能会导致进一步的改进。如果优化通过后没有发现改进,则结束优化。仅在优化时适用。
用法:OK,貌似默认5遍就够了

-allowaccessmodification 指定在处理期间可以扩展类和类成员的访问修饰符。这可以改善优化步骤的结果。
用法:OK,是的,看起来改进了优化

-dontpreverify 当面向 Android 时,preverifing 不是必需的,所以不要preverify 将其关闭以减少一点处理时间。但是这个选项不会影响代码的不可破坏性。
用法:OK,只是稍微减少处理时间

-dontusemixedcaseclassnames 指定在混淆时不生成大小写混合的类名。默认情况下,混淆的类名可以包含大写字符和小写字符的混合。这将创建完全可接受和可用的罐子。
用法:QUESTIONABLE,我找不到添加此选项的确切原因,但看起来将类名从 abcdef 更改为 AbSdEf 不会使代码牢不可破

-dontskipnonpubliclibraryclasses 指定不忽略非公共库类。从 4.5 版开始,这是默认设置。
用法:OK,很有用

proguard-android-optimize.txt 中不包含以下选项:

-mergeinterfacesaggressively 指定可以合并接口,即使它们的实现类没有实现所有接口方法...设置此选项会降低某些 JVM 上已处理代码的性能
用法:BAD,对Android来说看起来很危险,不要包含在配置中,禁止类/合并/优化的总结

-overloadaggressively 指定在混淆时应用积极的重载。然后,多个字段和方法可以获得相同的名称,只要它们的参数和返回类型不同,这是 Java 字节码所要求的(不仅仅是它们的参数,是 Java 语言所要求的)
用法:BAD,Google 的 Dalvik VM 无法处理重载的静态字段。

所以我只知道一个更有用的混淆和非危险选项:
-repackageclasses ''

-repackageclasses '' 指定通过将所有重命名的类文件移动到单个给定包中来重新打包它们。如果没有参数或使用空字符串 (''),则会完全删除包。此选项会覆盖 -flattenpackagehierarchy 选项。
用法:OK,由 Google 使用,所以看起来我们至少找到了可以添加到配置中的选项

另外请注意解码堆栈跟踪。 ProGuard 还会从堆栈跟踪中删除文件名和行号。这使得查找错误变得非常复杂。您可以通过将以下代码添加到配置中来保留行号:

-renamesourcefileattribute SourceFile 
-keepattributes SourceFile,LineNumberTable

这将保留行号,但将堆栈跟踪中的文件名替换为“SourceFile”。

另外不要忘记,ProGuard 看起来很容易受到攻击,因为它不加密字符串资源,因此请考虑使用 DexGuard 或自己加密重要的字符串(如令牌、url)。

【讨论】:

    【解决方案2】:

    根据优化文件中的评论,优化会带来一定的风险,如果使用,必须彻底测试应用程序。根据我的经验,有必要禁用代码/简化/高级,因为它导致在 lambda 外部初始化的最终局部变量在 lambda 内部为 NULL。调试和查找非常困难。因此我的优化设置如下:

    -优化 !code/simplification/cast,!code/simplification/advanced,!field/*,!class/merging/*,!method/removal/parameter,!method/propagation/parameter

    请注意,如果您的目标是 Android 2.0 及更低版本(这不太可能),还必须禁用代码/简化/算术。除此之外,我还必须禁用方法/删除/参数和方法/传播/参数,因为这些隐式启用代码/简化/高级(有关更多信息,请参阅ProGuard manual)。

    【讨论】:

      【解决方案3】:

      在 libminecraft 1.15.2 零,第一个使用新 libminecraft 先进技术全程序优化的 Minecraft 版本中,我只使用了 gson、内联和代码优化。这样做是为了减轻使用完全优化可能带来的不稳定影响。

      现在我们有了 Minecraft 1.16.2 和 ProGuard 7.0.0,我使用了完整的优化,没有任何稳定性问题(我实际上将 ProGuard 与 Allatori 堆叠在一起,但仍然没有遇到稳定性问题,因为 Allatori 在控制和数据流优化方面比ProGuard)。

      我在 libminecraft 1.16.2 中运行了 3 次 ProGuard。一次只进行 5 次代码优化,一次进行所有非代码优化,一次进行 2 次代码优化。此外,我使用 Allatori 进行最后的优化,因为它执行非常高质量的控制和数据流优化。

      【讨论】:

        猜你喜欢
        • 2014-06-01
        • 1970-01-01
        • 2021-05-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-25
        相关资源
        最近更新 更多