面向库作者的优化

作为库作者,您应确保应用开发者能够轻松将您的库集成到其应用中,同时保持高质量的最终用户体验。您应确保您的库无需额外设置即可与 Android 优化兼容,或者说明该库可能不适合在 Android 上使用。

本文档面向发布库的开发者,但对于大型模块化应用中的内部库模块开发者来说,也可能很有用。

如果您是应用开发者,并希望了解如何优化 Android 应用,请参阅启用应用优化。如需了解哪些库适合使用,请参阅明智地选择库

使用 codegen 而非反射

尽可能使用代码生成(codegen,而不是反射。在编程时,代码生成和反射都是避免样板代码的常用方法,但代码生成与 R8 等应用优化器更兼容:

  • 借助 codegen,系统会在构建过程中分析和修改代码。由于编译时间之后不会进行任何重大修改,因此优化器知道最终需要哪些代码,哪些代码可以安全地移除。
  • 借助反射,系统会在运行时分析和操控代码。由于代码在执行之前不会真正完成,因此优化器不知道哪些代码可以安全移除。它可能会移除在运行时通过反射动态使用的代码,从而导致用户应用崩溃。

许多现代库使用 codegen 而非反射。如需了解 RoomDagger2 等众多库使用的通用入口点,请参阅 KSP

何时可以进行反思

如果您必须使用反射,则应仅反射到以下任一位置:

  • 特定的目标类型(特定的接口实现者或子类)
  • 使用特定运行时注解的代码

以这种方式使用反射可以限制运行时开销,并支持编写有针对性的使用方保留规则

这种特定且有针对性的反射形式是一种模式,您可以在 Android 框架(例如在膨胀 activity、视图和可绘制对象时)和 AndroidX 库(例如在构建 WorkManager ListenableWorker 或 RoomDatabase 时)中看到这种模式。相比之下,Gson 的开放式反射不适合在 Android 应用中使用

编写使用方保留规则

库应打包“使用方”保留规则,这些规则的格式与应用保留规则相同。这些规则会捆绑到库工件 (AAR 或 JAR) 中,并在 Android 应用优化期间使用该库时自动被使用。

AAR 库

如需为 AAR 库添加使用方规则,请在 Android 库模块的 build 脚本中使用 consumerProguardFiles 选项。如需了解详情,请参阅我们的有关创建库模块的指南

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

Groovy

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

JAR 库

如需将规则与以 JAR 形式分发的 Kotlin/Java 库捆绑在一起,请将规则文件放在最终 JAR 文件的 META-INF/proguard/ 目录中,并使用任意文件名。例如,如果您的代码位于 <libraryroot>/src/main/kotlin,请将使用方规则文件放在 <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro 中,系统会将规则打包到输出 JAR 的正确位置。

通过检查规则是否位于 META-INF/proguard 目录中,验证最终 JAR 是否正确捆绑了规则。

支持不同的缩减工具(高级)

您可以根据目标特定缩减工具(R8 或 ProGuard)以及特定缩减工具版本来量身定制规则。这样,您的库便可以在使用新缩减工具版本的项目中以最佳方式运行,同时允许在使用旧版缩减工具的项目中继续使用现有规则。

如需指定目标缩减规则,您需要在 AAR 或 JAR 库内的特定位置添加这些规则,如下所述。

In an AAR library:
    consumer-proguard-rules.pro (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

这意味着,有针对性缩减规则的 JAR 存储在 JAR 的 META-INF/com.android.tools 目录中,而有针对性缩减规则的 AAR 存储在 AAR 的 classes.jar 内的 META-INF/com.android.tools 目录中。

该目录下可以有多个目录,其名称采用 r8-from-<X>-upto-<Y>proguard-from-<X>-upto-<Y> 的形式,用于指明目录中的规则是为哪个版本的哪个缩减程序编写的。请注意,-from-<X> 和 -upto-<Y> 部分是可选的,<Y> 版本是排他的,版本范围必须连续。

例如,r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0r8-from-8.2.0 可以组成有效的一组目标缩减规则。R8 将使用 r8-from-8.0.0-upto-8.2.0 目录下的规则,从 8.0.0 版到 8.2.0 版(不包括 8.2.0 版)。

有了这些信息,Android Gradle 插件便可从匹配的 R8 目录中选择规则。如果库未指定目标缩减规则,Android Gradle 插件将从旧版位置(对于 AAR 为 proguard.txt,对于 JAR 为 META-INF/proguard/<ProGuard-rules-file>)选择规则。