isMinifyEnabled = true

启用缩减功能(可移除未使用的代码)、混淆处理功能(可缩短应用的类和成员的名称)以及优化功能(可应用经过改进的代码优化策略,以进一步缩减应用大小并提升应用性能)。本页将介绍 R8 如何为您的项目执行这些编译时任务以及如何自定义这些任务。

当您使用 Android Gradle 插件 3.4.0 或更高版本构建项目时,该插件不再使用 ProGuard 执行编译时代码优化,而是与 R8 编译器协同工作,处理以下编译时任务:在构建应用的发布版本时,您可以将 R8 配置为执行上述编译时任务。您还可以停用某些任务或通过 ProGuard 规则文件自定义 R8 的行为。事实上,R8 支持所有现有 ProGuard 规则文件,因此您在更新 Android Gradle 插件以使用 R8 时,无需更改现有规则。

启用缩减、混淆处理和优化功能:当您使用 Android Studio 3.4 或 Android Gradle 插件 3.4.0 及更高版本时,R8 是默认编译器,用于将项目的 Java 字节码转换为在 Android 平台上运行的 DEX 格式。不过,当您使用 Android Studio 创建新项目时,缩减、混淆处理和代码优化功能默认处于停用状态。这是因为,这些编译时优化功能会增加项目的构建时间,而且如果您没有充分自定义要保留的代码,还可能会引入错误。因此,在构建应用的最终版本(也就是在发布应用之前测试的版本)时,最好启用这些编译时任务。如需启用缩减、混淆处理和优化功能,请在项目级构建脚本中添加以下代码。

R8 配置文件:R8 使用 ProGuard 规则文件来修改其默认行为并更好地了解应用的结构,比如充当应用代码入口点的类。虽然您可以修改其中一些规则文件,但某些规则可能由编译时工具(如 AAPT2)自动生成,或从应用的库依赖项继承而来。下表介绍了 R8 使用的 ProGuard 规则文件的来源。

```

/proguard-rules.pro

proguard-rules.pro

proguard-android-optimize.txt@Keep*proguard-android-optimize.txt

proguard.txt

META-INF/proguard/

minifyEnabled true

```

以下是根据提供的内容重构的代码:

```java

// 在项目的 build.gradle 文件中,添加 R8 或 ProGuard 配置

android {

// ...

buildTypes {

release {

minifyEnabled true

proguardFiles getDefaultProguardFile('proguard-rules.pro'), 'proguard-rules-r8.pro'

}

}

}

// 在项目的 build.gradle 文件中,将缩减规则添加到 AAR 或 JAR 库内的特定位置

dependencies {

implementation(name: 'your_library_name', ext: 'aar') {

// 将 R8 或 ProGuard 配置文件放在指定路径下,例如:/build/intermediates/aapt_proguard_file/.../aapt_rules.txt

artifactFileName = file("$projectDir/path/to/your_library_name-release.aar")

artifactVersion = "1.0.0"

configuration = configurations.getByName("release")

configuration.isMinified = true

configuration.minificationRules = file("$projectDir/path/to/your_library_name-release.aar/src/main/proguard/proguard-rules-r8.pro")

}

}

```

请确保将 `your_library_name`、`path/to/your_library_name-release.aar` 替换为实际的库名称和路径。

在 AAR 库中,文件结构如下:

```

proguard.txt (legacy location)

classes.jar

└── META-INF

└── com.android.tools (targeted shrink rules location)

├── r8-from--upto-/

└── proguard-from--upto-/

```

在 JAR 库中,文件结构如下:

```

META-INF

├── proguard/ (legacy location)

└── com.android.tools (targeted shrink rules location)

├── r8-from--upto-/

└── proguard-from--upto-/

```

其中,`com.android.tools` 是针对目标缩减规则的位置。开发者可以选择在其库中添加目标缩减规则或旧版 ProGuard 规则,如果他们希望与版本低于 3.6 的 Android Gradle 插件或其他工具保持兼容性,则可以同时添加这两种规则。

此外,还可以添加其他配置,例如 `/proguard-rules.pro`,其中包含 ProGuard 文件列表。

以下是重构后的代码:

```markdown

# Product Flavors

## Proguard Files

- **flavor2** - rules.pro

- **flavor2** - flavor2

- **flavor2** - release

# Test Proguard Files

- minifyEnabled: true

# Code Minification (Tree Pruning)

代码缩减(也称为“摇树优化”)是指移除 R8 确定在运行时不需要的代码的过程。此过程可以大大减小应用的大小,例如,当您的应用包含许多库依赖项,但只使用它们的一小部分功能时。

为了缩减应用的代码,R8 首先会根据组合的配置文件集确定应用代码的所有入口点。这些入口点包括 Android 平台可用来打开应用的 activity 或服务的所有类。从每个入口点开始,R8 会检查应用的代码来构建一张图表,列出应用在运行时可能会访问的所有方法、成员变量和其他类。系统会将与该图表没有关联的代码视为执行不到的代码,并可能会从应用中移除该代码。

| 类名 | 方法/成员变量 |

| --- | --- |

| MainActivity.class | foo() | faz() | bar() |

| OkayApi.class | baz() |

图 1.

编译时,R8 会根据项目的组合保留规则构建一张图表,用于确定执行不到的代码。

```proguard

-keep

```

如果您只想减小应用资源的大小,请跳到介绍如何缩减资源的部分。请注意,如果缩减了库项目,则依赖于该库的应用会包含缩减后的库类。如果库 APK 中缺少类,您可能需要调整库保留规则。如果您以 AAR 格式构建和发布库,则您的库所依赖的本地 JAR 文件在 AAR 文件中不会缩小。

自定义要保留的代码:

```proguard-android-optimize.txt

```

当应用通过 Java 原生接口 (JNI) 调用方法时:

```proguard-android-optimize.txt

```

当您的应用在运行时查询代码时(如使用反射):

```proguard-android-optimize.txt

```

在Android Vitals中,您可以通过启用经过符号化解析的原生代码崩溃堆栈轨迹来报告原生代码崩溃问题。以下是一些步骤:

1. 打开Google Play管理中心。

2. 在左侧菜单中,选择“应用”。

3. 选择要报告崩溃的应用。

4. 在右侧面板中,选择“Android Vitals”选项卡。

5. 在“原生代码崩溃”部分下,单击“添加崩溃”。

6. 在弹出窗口中,选择“生成并上传原生代码调试符号文件”。

7. 根据您的项目使用的Android Gradle插件版本和构建输出,按照相应的步骤生成和上传符号文件。

8. 对于Android Gradle插件版本4.1或更高版本的项目,请在build.gradle.kts文件中设置调试符号级别:

```kotlin

android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }

```

9. 对于Android Gradle插件版本4.0或更低版本(及其他构建系统)的项目,您需要在构建流程中保留未移除的库的副本。这可以通过在项目目录中创建一个名为app/build/intermediates/cmake/universal/release/obj的文件夹来实现。在该文件夹中,您将看到类似于以下结构的子文件夹:armeabi-v7a、arm64-v8a、x86和x86_64。这些文件夹包含了不同架构的库文件(如libgameengine.so、libothercode.so和libvideocodec.so)。

10. 最后,回到Google Play管理中心,单击“添加崩溃”按钮,然后上传生成的符号文件以报告原生代码崩溃问题。

请根据以下内容完成重构,并保持段落结构:

```

zip -r symbols.zip .

缩减资源

资源缩减只有在与代码缩减配合使用时才能发挥作用。在代码缩减器移除所有不使用的代码后,资源缩减器便可确定应用仍要使用的资源,当您添加包含资源的代码库时尤其如此。您必须移除不使用的库代码,使库资源变为未引用资源,因而可由资源缩减器移除。

shrinkResourcesminifyEnabledtrue

minifyEnabledshrinkResourcesproguard-rules.pro

自定义要保留的资源

tools:keeptools:discard

例如:

```xml

```

res/raw/my.package.keep.xmlkeepmy.package.build.variant.keep.xmlkeep启用严格引用检查通常,资源缩减器可以准确地判断是否使用了某个资源。不过,如果您的代码会调用 (或者您的任何库会执行此调用,例如 AppCompat 库便会执行此调用),这意味着您的代码将根据动态生成的字符串查询资源名称。当您启用严格引用检查时,资源缩减器在默认情况下会采取保护行为,将所有具有匹配名称格式的资源标记为可能已使用,无法移除。

img_res/raw/file:///android_res/drawable//ic_plus_anim_016.pngkeep.xmlshrinkModestrict

以下是重构后的代码:

```xml

tools:shrinkMode="strict">

保留未使用的备用资源

设置只保留英语和法语的语言资源

合并重复资源

只有在两个或更多个文件具有完全相同的资源名称、类型和限定符时,才会进行资源合并。Gradle 会在重复项中选择它认为最合适的文件(根据下述优先顺序),并且只将这一个资源传递给 AAPT,以便在最终工件中分发。

sourceSet src/main/res/src/main/res2/

对代码进行混淆处理

```

在Android项目中,混淆处理可以显著减小应用的大小。虽然混淆处理不会从应用中移除代码,但如果应用的DEX文件将许多类、方法和字段编入索引,那么混淆处理将可以显著缩减应用的大小。不过,由于混淆处理会对代码的不同部分进行重命名,因此在执行某些任务(如检查堆栈轨迹)时需要使用额外的工具。如需了解混淆处理后的堆栈轨迹,请参阅介绍如何解码经过混淆处理的堆栈轨迹的部分。

解码经过混淆处理的堆栈轨迹:R8 对代码进行混淆处理后,理解堆栈轨迹的难度将会极大增加,因为类和方法的名称可能有变化。如需获取原始堆栈轨迹,您应对堆栈轨迹进行轨迹还原。

代码优化:为了进一步优化应用,R8 会在更深层次的层面上检查代码,以移除更多未使用的代码,或尽可能重写代码,使其更简洁。下面是此类优化的几个示例:

```java

else {} else {}

-optimizations-optimizationpasses

```

请注意,启用优化将更改应用的堆栈轨迹。例如,进行内嵌会移除堆栈帧。如需了解如何获取原始堆栈轨迹,请参阅轨迹还原部分。

对运行时性能的影响:如果同时启用缩减、混淆和优化,R8 最多可将代码的运行时性能(包括界面线程上的启动时间和帧时间)提升 30%。停用其中任何一项都会大大限制 R8 使用的优化组。如果启用了 R8,您还应创建启动配置文件,以获得更好的启动性能。

启用增强型优化:R8 包含一组额外的优化功能(称为“完整模式”),这使得它的行为与 ProGuard 不同。从 Android Gradle 插件版本 8.0.0 开始,这些优化功能默认处于启用状态。要禁用这些功能,可以在 gradle.properties 文件中设置 android.enableR8.fullMode 为 false。

这些额外的优化功能会使 R8 的行为与 ProGuard 不同,因此如果您使用的是专为 ProGuard 设计的规则,则可能需要添加额外的 ProGuard 规则,以避免运行时问题。例如,假设您的代码通过 Java Reflection API 引用一个类。

不使用“完整模式”时,R8 会假设您打算在运行时检查和操纵该类的对象(即使您的代码实际上并不这样做),因此它会自动保留该类及其静态初始化程序。不过,使用“完整模式”时,R8 不会做出此假设。如果 R8 断言您的代码在运行时从未使用该类,则会将该类从应用的最终 DEX 中移除。也就是说,如果您想保留类及其静态初始化程序,则需要在规则文件中添加保留规则才能实现这一点。

如果您在使用 R8 的“完整模式”时遇到任何问题,请参阅 R8 常见问题解答页面,寻找可能的解决方案。如果您无法解决问题,请报告错误。

对堆栈轨迹进行轨迹还原:经过 R8 处理的代码会发生各种更改,这可能会使堆栈轨迹更难以理解,因为堆栈轨迹与源代码不完全一致。如果未保留调试信息,就可能会出现行号更改的情况。这可能是由内嵌和轮廓等优化造成的。影响最大的因素是混淆处理;进行混淆处理时,就连类和方法的名称都会更改。为了还原原始堆栈轨迹,R8 提供了 retrace 命令行工具,该工具与命令行工具软件包捆绑在一起。

以下是重构后的内容:

请使用以下命令行参数来解决 R8 的问题:

-keepattributes LineNumberTable,SourceFile -renamesourcefileattribute SourceFile

LineNumberTableSourceFile-renamesourcefileattributeSourceFile

在排查 R8 问题时,请参考本部分提供的策略。如果您无法在本文中找到相关问题的解决方案,还请查阅 R8 常见问题解答页面和 ProGuard 的问题排查指南。

要生成移除的(或保留的)代码的报告,请使用以下命令行参数:

-printusage

/usage.txt

请根据提供的内容完成内容重构,并保持段落结构:

- androidx.drawerlayout.R$attr

- androidx.vectordrawable.R

- androidx.appcompat.app.AppCompatDelegateImpl

```java

public void setSupportActionBar(androidx.appcompat.widget.Toolbar);

public boolean hasWindowFeature(int);

public void setHandleNativeActionModesEnabled(boolean);

public android.view.ViewGroup getSubDecor();

public void setLocalNightMode(int);

final androidx.appcompat.app.AppCompatDelegateImpl$AutoNightModeManager getAutoNightModeManager();

public final androidx.appcompat.app.ActionBarDrawerToggle$Delegate getDrawerToggleDelegate();

private static final boolean DEBUG;

private static final java.lang.String KEY_LOCAL_NIGHT_MODE;

static final java.lang.String EXCEPTION_HANDLER_MESSAGE_SUFFIX;

```

当您在Android项目中进行资源缩减时,Gradle会显示一个窗口来概述从应用中移除的资源及其数量。例如,如果移除了33%的未使用资源,那么这些信息就会出现在窗口中。

此外,如果您使用的是Android Gradle插件的非严格模式,那么在存在看似可用于为动态加载资源构建资源名称的字符串常量时,就可能将资源ID标记为“可执行到”。这是因为这种类型的资源在运行时可能会被动态更改或替换,而在构建过程中无法准确地确定其值。因此,为了避免这种情况,建议在使用这种资源类型时,将其ID标记为不可执行到。

以下是一个示例:

```groovy

android {

...

defaultConfig {

...

lintOptions {

disable 'UnusedResource'

}

}

lintOptions {

checkReleaseBuilds false

}

}

```

在这个示例中,我们禁用了`UnusedResource`警告,并且在检查发布版本时关闭了lint。这样,我们在开发过程中就可以使用看似可用于为动态加载资源构建资源名称的字符串常量,而不会在构建输出中看到警告。

在10:32:50.590时刻,系统输出了一条调试信息。该信息表示正在标记一个名为"ic_plus_anim_016:2130837506"的可绘制对象。原因是它的格式字符串与字符串池常量"ic_plus_anim_%1$d"匹配,因此将其标记为已使用。然后,工具会丢弃这个可绘制对象。

以下是重构后的代码示例(Java):

```java

System.out.println("[QUIET] [system.out] Marking drawable: " + "ic_plus_anim_016:2130837506" + " used because it format-string matches string pool constant " + "ic_plus_anim_%1$d.");

```

重构后的代码保持了原始信息的完整性和格式,并使用了合适的输出语句来显示调试信息。