保留规则简介

当您使用默认设置启用应用优化时,R8 会执行广泛的优化,以最大限度地提升性能。R8 会对代码进行重大修改,包括重命名、移动和移除类、字段和方法。如果您发现这些修改会导致错误,则需要通过在保留规则中声明 R8 不应修改的代码部分来指定这些部分。

需要 keep 规则的常见场景

R8 会识别并保留代码中的所有直接调用。不过,R8 无法看到间接代码使用情况,这可能会导致它移除应用所需的代码,从而导致崩溃。使用 keep 规则告知 R8 保留此类间接使用的代码。以下是您可能需要保留规则的一些常见情况:

  • 通过反射访问的代码:R8 无法识别通过反射访问的类、字段或方法。例如,R8 无法识别使用 Class.getDeclaredMethod() 按名称查找的方法或使用 Class.getAnnotation() 检索的注解。在这些情况下,R8 可能会重命名这些方法和注解,或将其完全移除,从而导致在运行时出现 ClassNotFoundException 或 NoSuchMethodException。
  • 从 Java 原生接口 (JNI) 调用的代码:当原生(C 或 C++)代码调用 Java 或 Kotlin 方法,或者 Java 或 Kotlin 代码通过 JNI 调用 C++ 代码时,调用基于方法名称的动态字符串查找。R8 无法看到基于字符串的动态方法调用,因此其优化可能会破坏您的代码。

此列表并未详尽列出需要保留规则的所有场景,但涵盖了您可能需要保留规则的大多数情况。

如果您的代码使用反射或从 JNI 调用,您可以使用 Jetpack Keep 注解来注解该代码,而不是手动编写保留规则。其 Gradle 插件会在构建时根据注解生成保留规则。

了解保留规则对优化的影响

R8 是一款全程序优化工具,可分析应用代码,以移除未使用的代码、内联方法、合并类和混淆标识符。不过,R8 只能在您定义的配置范围内进行优化。

保留规则代表限制优化的明确指令。您声明的每条保留规则都会限制 R8 转换代码库中相应部分的能力。精心设计的保留规则的价值在于其具体性:

  • 精细的保留规则可实现最大程度的优化:通过仅定位动态访问的确切入口点(例如反射构造函数或序列化字段),您可以让 R8 优化其余代码。

  • 宽泛的保留规则会阻碍优化:声明包级规则或宽泛的通配符会阻止 R8 优化整个类及其所有成员。R8 无法移除、内嵌、合并或混淆该代码。

过于宽泛的保留规则会直接导致 DEX 二进制文件膨胀、应用内存占用增加、启动时间(TTID 和 TTFD)变慢以及 ANR 发生率升高。 您的目标不应是“以防万一”而保留类,而是定义动态执行所需的最小协定。

如需查找宽泛或不必要的保留规则(包括来自第三方库的规则),请使用 R8 配置分析器。它会报告缩减、优化和混淆处理得分,这些得分反映了 R8 可以优化多少代码。

如何向应用添加 keep 规则

保留规则配置取决于您使用的 AGP 版本。

大型应用通常在多个库模块中包含代码。在这种情况下,通常最好将保留规则与它们所适用的代码一起放在特定库模块中。维护库的保留规则的关键区别在于,您如何在库模块的 build.gradle.kts(或 build.gradle)文件中声明这些规则。如需了解详情,请参阅针对库作者的优化。

对于 AGP 9.3 及更高版本

将规则添加到 src/<variant>/keepRules 目录中后缀为 .keep 的文件中。例如 src/main/keepRules/custom-rules.keep。请注意,使用适用于 AGP 9.3 及更高版本的更新版 DSL 可同时启用代码和资源优化,并且不需要您明确定义默认的 Android 保留规则文件 (proguard-android-optimize.txt),因为该文件默认包含在内,除非明确省略。

Kotlin

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
            }
        }
    }
}

Groovy

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
            }
        }
    }
}

忽略默认的 Android 平台保留规则(高级)

AGP 提供了一组默认的 Android 平台规则。如需从项目的配置中省略这些规则并自行管理所有保留规则,请将 optimization.keepRules.includeDefault 设置为 false。

Kotlin

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
                keepRules {
                    includeDefault = false // The file with optimization
                    // rules for the Android platform is included by
                    // default. To omit this file, set this option to false.
                }
            }
        }
    }
}

Groovy

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
                keepRules {
                    includeDefault = false // The file with optimization
                    // rules for the Android platform is included by
                    // default. To omit this file, set this option to false.
                }
            }
        }
    }
}

适用于 9.3 以下 AGP 版本的旧版 DSL

将规则添加到位于应用模块根目录中的 proguard-rules.pro 文件中。该文件可能已经存在,但如果不存在,请创建它。如需应用文件中的规则,您必须在模块级 build.gradle.kts(或 build.gradle)文件中声明该文件。

默认情况下,您的 build 文件还包含 proguard-android-optimize.txt 文件。此文件包含大多数 Android 项目所需的规则,因此您应将其保留在 build 文件中。此文件基于 proguard-common.txt 文件,并与其共享内容。

旧版 DSL (Kotlin)

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true

            proguardFiles(
                // Default file with default optimization rules.
                getDefaultProguardFile("proguard-android-optimize.txt"),
                ...
            )
        }
    }
}

旧版 DSL (Groovy)

android {
    buildTypes {
        release {
            minifyEnabled = true
            shrinkResources = true

            // Default file with default optimization rules.
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
            ...
        }
    }
}

添加保留规则

添加保留规则时,您可以添加全局选项,也可以定义自己的保留规则。

  • 全局选项:全局选项是影响 R8 如何在整个代码库中运行的常规指令。如需了解详情,请参阅全局选项。

  • 保留规则:保留规则需要精心设计,以确保在最大限度地优化代码与避免意外破坏应用之间取得适当的平衡。如需了解如何编写保留规则,请参阅添加保留规则。

针对库作者的保留规则

在了解保留规则的全局选项和语法后,请参阅针对库作者的优化,了解更多详情。