遵循最佳实践

在使用保留规则时,请务必达到适当的特异性,以确保您在保持应用行为的同时获得好处。请参阅以下部分,了解保留规则中的良好用法以及需要避免的事项。

保留规则的良好用法

定义明确的保留规则应尽可能具体,并遵循以下模式:

  • 对于类规范,请尽可能始终指定特定类、基类或带注解的类,如以下示例所示:

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • 尽可能在源代码中使用注解,然后在保留规则中直接以这些注解为目标。这样会在代码与保留代码的规则之间建立清晰明确的链接,使配置更稳健、更易于理解,并且在代码更改时不易中断。

    例如,以下代码段演示了如何保留 MyClass 类以及使用 @com.example.DisplayComponent 注解的其他类:

    // In the source code
    @com.example.DisplayComponent
    class MyClass { /* ... */ }
    
    // In the keep rules
    -keep @com.example.DisplayComponent class * {*;}
    

    我们建议您为注解命名,以便它们为保留代码部分的原因提供有意义的上下文。例如,对于显示组件需要保留某些部分的应用,请使用 @DisplayComponent。

  • 尽可能声明成员规范,并且仅引用应用必须保留才能正常运行的类部分。 建议不要通过将可选成员范围定义为 { *; } 来将规则应用于整个类,除非有严格的需要。

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    
  • 如果您使用 repackageclasses 全局选项,请避免指定 可选的软件包名称。这样可以生成较小的 DEX 文件,因为在重新打包的类名称中省略了软件包前缀。

  • 为通过反射访问的所有项维护保留规则。即使 R8 在没有明确保留规则的情况下保留了此类项,维护实际规则也至关重要,因为未来的代码更改可能会导致 R8 不再保留这些项。

    对于您自己的代码中的反射,您可以使用 Jetpack Keep 来 生成更易于维护的保留规则。每个注解都位于执行反射的代码中,因此当您更改该代码时,您可以在同一位置更新或移除其注解。这样,规则就不会保留应用不再反射的代码。Lint 还会标记未注解的反射调用。

  • 如果可以,请使用 -assumenosideeffects 或 -convertchecknotnull 来优化 null 检查,因为这可以显著减小应用的 DEX 大小。如需了解详情,请参阅其他规则类型。

如果您无法遵守这些准则,可以暂时将需要保留的代码隔离到专用软件包中,并将保留规则应用于该软件包。不过,这并非长期解决方案。如需了解详情,请参阅 逐步采用优化。如需为软件包使用保留规则,请按以下示例所示定义保留规则:

-keepclassmembers class com.example.pkg.** { *; }

需要避免的事项

保留规则语法有很多选项,但为了获得可衡量的可持续性能优势,我们建议不要使用以下选项:

  • 请勿长期使用软件包级保留规则,例如 -keep class com.example.pkg.** { *; }。在配置 R8 时,可以暂时使用它们来解决问题。如需了解详情,请参阅限制优化范围。 一般来说,请谨慎使用通配符,确保仅保留所需代码。
  • 如果可以,请避免使用建议您在使用时复制和粘贴保留规则的库,尤其是软件包级保留规则。旨在 在 Android 上表现良好的库应尽可能避免反射,并 在必要时嵌入使用者保留规则。
  • 避免在保留规则中使用反转运算符 !,因为您可能会无意中将规则应用于应用中的几乎每个类。

如果您无法遵循这些规则,则可能使用了大量开放式 反射,应避免反射或避免使用反射的库(请参阅 Gson 案例研究)。