【问题标题】:Can anyone explain the Proguard configuration setting: -keep @interface *谁能解释 Proguard 配置设置:-keep @interface *
【发布时间】:2018-10-02 09:17:37
【问题描述】:

这是有问题的配置设置:-keep @interface *

这篇文章引用了这个设置:https://stackoverflow.com/a/17437740/367544

在 Proguard 手册中:https://www.guardsquare.com/en/proguard/manual/troubleshooting#notkept

但手册(或帖子)并未解释此配置设置如何或为何起作用。我认为这个配置值会保留您的应用程序中定义的所有注释。我在这里强调defined这个词,因为我想将它与used的注释进行比较。因此,如果我在我的代码中定义了一个注释,例如public @interface MyAnnotation {},那么我希望这个配置设置能够保留它。但是,如果我要在像 public class MyClass { @MyAnnotation public void run(){} } 这样的另一个类中使用我的注释,那么我会期望此配置设置将其保留在那里。我认为要保留使用注释的位置,您需要像-keep class * { @interface <methods>; } 这样的设置。但是,我的理解显然是错误的,因为-keep @interface * 配置设置确实保留了它们使用的注释。

谁能解释为什么-keep @interface * 配置设置会影响在其他类中使用它们的注释?此外,Proguard 手册根本没有解释如何使用 @interface 关键字。这就像任何注释的通配符吗?还是像我的示例public @interface MyAnnotation {} 那样引用注释的定义?还是完全是另外一回事?

【问题讨论】:

    标签: java annotations proguard shrink


    【解决方案1】:

    编译每个接口时,即使使用 proguard,它也应该创建一个可以在 java 虚拟机中使用的有效类文件。 Java 有特定的命名规则,用于将包中的接口和类与文件连接起来。

    例如,即使包com.mycompany.mypackage 的接口VeryImportantInterface 被混淆,结果你会得到: 接口a 在包b.c.d 中 java 期望在包b.c.d 中的一个名为a.class 的文件中找到接口a

    类似的规则适用于内部类和接口。

    因此,如果您确实混淆了类或接口的定义,则必须在任何地方使用其混淆名称来提及它。否则,例如类 MyClass.class 被混淆为 a.class 和另一个类,例如MyClassReference 仍将此类引用为MyClass,然后MyClassReference 第一次尝试使用MyClass 时将抛出ClassNotFoundException

    关于-保持@interface *ProGuard RefCard 中指定

    'keep' 防止类和类成员被删除或重命名。

    ProGuard RefCard还提到可以使用通配符*

    1. * 可用于任意数量的字符(但不能用于包分隔符)
    2. 类名* 指代任何类,与它的包无关。
    3. * 匹配任何字段或方法

    因此,根据上述定义,-keep @interface * 适用于public @interface MyAnnotation {},因为它的名称与通配符* 匹配。由于根据定义MyAnnotation 不会被移除,所以它不会从任何地方移除。

    相反,-keep class * { @interface <methods>; } 更具体,只会保留注解的用法。

    要考虑的另一件事是keep 后跟Class specification。并基于Class specification

    @ 规范可用于将类和类成员限制为使用指定注解类型注解的类和类成员。一个注解类型就像一个类名一样被指定。

    在收缩过程中,proguard 将删除所有直接或间接使用的方法和成员以及-keep 指定的方法和成员。但是它没有明确提到它对注释的作用。 Pro-Guard 提到缩小以下内容:

    默认情况下,应用收缩;所有类和类成员都被删除,除了由各种 -keep 选项列出的那些以及它们直接或间接依赖的那些。 Shrinking Options 因此,一种情况可能是 pro-guard 以某种方式检测到注释被使用并防止它在收缩过程中被删除。 另一种情况是注释被视为方法的元数据而不被视为成员。 在 proguard 文档中确实不明显或没有很好的记录。

    您可以使用-whyareyoukeeping @interface *-verbose 从 Prog-Guard 获得关于保留相关接口的原因的反馈。

    更新: 由于上述配置指令的结果是: ... is kept by a directive in the configuration.,只能断定-keep @interface *其实。因此,它没有提供任何额外的说明。没有对 Pro-Guard 文档的任何具体解释,我认为以下两种可能的解释是可能的: 1. proguard收缩步骤考虑到注释在代码的某些部分使用,因此需要而不是减少。 2. class_specification @interface * 匹配带注释的方法和注释声明。

    【讨论】:

    • 感谢您的回复,但我觉得您只是确认了我的问题。首先,正如我所提到的,我只是在缩小,而不是混淆。正如你所说,@ 987654356@ 应该只适用于注释的定义 就像你的例子public @interface MyAnnotation {} - 但我的问题的重点是这不是 实际发生了什么。这个-keep @interface * 命令将注释保留在使用的位置(请重新阅读我的原始帖子以获取更多上下文)。我试图理解为什么。
    • 我将重新措辞以使答案更清楚,该答案涵盖了您的问题。感谢您指出您的评论正在缩小。我刚刚注意到您问题中的收缩标签。我只看过正文,没有提到。
    • PS:你是对的,答案并没有清楚地回答你的问题,而且proguard文档确实没有提供足够的细节。您能否使用-whyareyoukeeping @interface *-whyareyoukeeping @*-verbose 从 Prog-Guard 获得关于保留相关接口的原因的反馈。您可以将其添加到您的问题中,我们可以尝试看看发生了什么。真的很有趣。
    • -whyareyoukeeping @* 选项不起作用,它只会引发错误。我尝试使用-whyareyoukeeping @interface * 配置运行,结果是:... is kept by a directive in the configuration. 不幸的是不是很有帮助:/
    • 感谢您的尝试!确实,它不是很有帮助。此注释是否有任何具体参考?比如使用反射来搜索注解?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 2017-04-07
    • 2015-12-21
    相关资源
    最近更新 更多