优化构建速度

较长的构建时间会减慢您的开发流程。此页面提供了一些有助于解决构建速度瓶颈的技术。

改进应用构建速度的一般流程如下所示

  1. 优化您的构建配置,执行几个步骤即可立即让大多数 Android Studio 项目受益。
  2. 分析您的构建,以识别和诊断可能特定于您的项目或工作站的一些更棘手的瓶颈。

在开发应用时,尽可能部署到运行 Android 7.0(API 级别 24)或更高版本的设备。较新版本的 Android 平台实现了更好的应用更新机制,例如 Android Runtime (ART) 和对 多个 DEX 文件 的原生支持。

注意:在第一次干净构建之后,您可能会注意到后续构建(干净构建和增量构建)的执行速度快得多,即使未使用此页面上描述的任何优化措施。这是因为 Gradle 守护程序有一个“预热”阶段,在此阶段性能会不断提高 - 这与其他 JVM 进程类似。

优化您的构建配置

请遵循以下提示来提高 Android Studio 项目的构建速度。

保持工具最新

Android 工具在几乎每次更新中都会获得构建优化和新功能。此页面上的某些提示假设您使用的是最新版本。要利用最新的优化措施,请保持以下内容最新

使用 KSP 而不是 kapt

Kotlin 注释处理工具 (kapt) 明显慢于 Kotlin 符号处理器 (KSP)。如果您正在编写带注释的 Kotlin 源代码并使用处理注释的工具(例如支持 KSP 的 Room),则需要 迁移到 KSP

避免编译不必要的资源

避免编译和打包您未测试的资源,例如其他语言本地化和屏幕密度资源。相反,只需为您的“dev”风格指定一种语言资源和屏幕密度,如下面的示例所示

Groovy

android {
    ...
    productFlavors {
        dev {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations "en", "xxhdpi"
        }
        ...
    }
}

Kotlin

android {
    ...
    productFlavors {
        create("dev") {
            ...
            // The following configuration limits the "dev" flavor to using
            // English stringresources and xxhdpi screen-density resources.
            resourceConfigurations("en", "xxhdpi")
        }
        ...
    }
}

尝试将 Gradle Plugin Portal 放在最后

在 Android 中,所有插件都位于 google()mavenCentral() 存储库中。但是,您的构建可能需要使用 gradlePluginPortal() 服务解析的第三方插件。

Gradle 按声明顺序搜索存储库,因此如果首先列出的存储库包含大多数插件,则可以提高构建性能。因此,请尝试通过将其放在 settings.gradle 文件中存储库块的最后,来实验 gradlePluginPortal() 条目。在大多数情况下,这可以最大程度地减少冗余插件搜索次数并提高构建速度。

有关 Gradle 如何遍历多个存储库的更多信息,请参阅 Gradle 文档中的 声明多个存储库

在调试构建中使用静态构建配置值

始终对进入清单文件或资源文件的属性使用静态值,用于调试构建类型。

使用动态版本代码、版本名称、资源或任何其他更改清单文件的构建逻辑,每次想要运行更改时都需要进行完整的应用构建,即使实际更改可能只需要热交换。如果您的构建配置需要此类动态属性,则将这些属性隔离到您的发布构建变体中,并保持调试构建的静态值,如下面的示例所示

  ...
  // Use a filter to apply onVariants() to a subset of the variants.
  onVariants(selector().withBuildType("release")) { variant ->
      // Because an app module can have multiple outputs when using multi-APK, versionCode
      // is only available on the variant output.
      // Gather the output when we are in single mode and there is no multi-APK.
      val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

      // Create the version code generating task.
      val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
          it.outputFile.set(project.layout.buildDirectory.file("versionCode${variant.name}.txt"))
      }

      // Wire the version code from the task output.
      // map will create a lazy Provider that:
      // 1. Runs just before the consumer(s), ensuring that the producer (VersionCodeTask) has run
      //    and therefore the file is created.
      // 2. Contains task dependency information so that the consumer(s) run after the producer.
      mainOutput.versionCode.set(versionCodeTask.flatMap { it.outputFile.map { it.asFile.readText().toInt() } })
  }
  ...

  abstract class VersionCodeTask : DefaultTask() {

    @get:OutputFile
    abstract val outputFile: RegularFileProperty

    @TaskAction
    fun action() {
        outputFile.get().asFile.writeText("1.1.1")
    }
  }

请参阅 GitHub 上的 setVersionsFromTask 示例,了解如何在项目中设置动态版本代码。

使用静态依赖版本

build.gradle 文件中声明依赖项时,避免使用动态版本号(末尾带加号的版本号,例如 'com.android.tools.build:gradle:2.+')。使用动态版本号可能会导致意外的版本更新、难以解决版本差异以及由于 Gradle 检查更新而导致的构建速度变慢。请改用静态版本号。

创建库模块

查找应用中可以转换为 Android 库模块 的代码。以这种方式模块化代码允许构建系统仅编译您修改的模块并缓存这些输出以供将来构建使用。模块化还可以使您在启用此优化时,更有效地进行 并行项目执行

为自定义构建逻辑创建任务

在您 创建构建配置文件 后,如果构建配置文件显示构建时间中相对较长的一部分用于 **配置项目** 阶段,请查看您的 build.gradle 脚本,并查找要包含在自定义 Gradle 任务中的代码。通过将一些构建逻辑移到任务中,您可以帮助确保仅在需要时才运行任务,结果可以缓存以供后续构建使用,并且如果启用 并行项目执行,则构建逻辑可以并行运行。要了解有关自定义构建逻辑任务的更多信息,请阅读 官方 Gradle 文档

提示:如果您的构建包含大量自定义任务,您可能希望通过 创建自定义任务类 来整理您的 build.gradle 文件。将您的类添加到 project-root/buildSrc/src/main/groovy/ 目录中;Gradle 会自动将这些类包含在项目中所有 build.gradle 文件的类路径中。

将图像转换为 WebP

WebP 是一种图像文件格式,它提供有损压缩(如 JPEG)以及透明度(如 PNG)。WebP 可以提供比 JPEG 或 PNG 更好的压缩效果。

减少图像文件大小,而无需执行构建时压缩,可以加快构建速度,尤其是在您的应用使用大量图像资源时。但是,您可能会注意到设备 CPU 使用率在解压缩 WebP 图像时略有增加。使用 Android Studio 可以轻松地 将图像转换为 WebP

禁用 PNG 压缩

如果您不 将 PNG 图像转换为 WebP,您仍然可以通过在每次构建应用时禁用自动图像压缩来加快构建速度。

如果您使用的是 Android Gradle 插件 3.0.0 或更高版本,则默认情况下会为“debug”构建类型禁用 PNG 压缩。要为其他构建类型禁用此优化,请将以下内容添加到您的 build.gradle 文件中

Groovy

android {
    buildTypes {
        release {
            // Disables PNG crunching for the "release" build type.
            crunchPngs false
        }
    }
}

Kotlin

android {
    buildTypes {
        getByName("release") {
            // Disables PNG crunching for the "release" build type.
            isCrunchPngs = false
        }
    }
}

由于构建类型或产品风格未定义此属性,因此您需要在构建应用的发布版本时手动将此属性设置为 true

尝试使用 JVM 并行垃圾收集器

可以通过配置 Gradle 使用的最佳 JVM 垃圾收集器来提高构建性能。虽然 JDK 8 默认配置为使用并行垃圾收集器,但 JDK 9 及更高版本配置为使用 G1 垃圾收集器

为了潜在地提高构建性能,我们建议使用并行垃圾收集器 测试您的 Gradle 构建。在 gradle.properties 中设置以下内容

org.gradle.jvmargs=-XX:+UseParallelGC

如果此字段中已设置了其他选项,请添加一个新选项

org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC

要衡量不同配置下的构建速度,请参阅 分析构建

增加 JVM 堆大小

如果您观察到构建速度缓慢,尤其是在 构建分析器 结果中垃圾回收占用了超过 15% 的构建时间,则应增加 Java 虚拟机 (JVM) 堆大小。在 gradle.properties 文件中,将限制设置为 4、6 或 8 GB,如下例所示

org.gradle.jvmargs=-Xmx6g

然后测试构建速度是否有所提高。确定最佳堆大小的最简单方法是稍微增加限制,然后测试构建速度是否得到足够的提高。

如果您还使用 JVM 并行垃圾收集器,则整行应如下所示

org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g

您可以通过打开 HeapDumpOnOutOfMemoryError 标志来分析 JVM 内存错误。这样做后,JVM 在内存不足时会生成堆转储。

使用非传递性 R 类

使用非传递性 R 可以为具有多个模块的应用提供更快的构建速度。这样做有助于防止资源重复,方法是确保每个模块的 R 类仅包含对其自身资源的引用,而不会从其依赖项中提取引用。这将导致更快的构建以及编译避免带来的相应好处。这是 Android Gradle 插件 8.0.0 及更高版本中的默认行为。

从 Android Studio Bumblebee 开始,非传递性 R 类在新建项目中默认启用。对于使用早期版本的 Android Studio 创建的项目,请将其更新为使用非传递性 R 类,方法是转到 **重构 > 迁移到非传递性 R 类**。

要了解有关应用资源和 R 类的更多信息,请参阅 应用资源概述

使用非常量 R 类

在应用和测试中使用非常量 R 字段,以提高 Java 编译的增量性并允许更精确地缩减资源。对于库,R 类字段始终不是常量,因为在为依赖该库的应用或测试打包 APK 时会对资源进行编号。这是 Android Gradle 插件 8.0.0 及更高版本中的默认行为。

禁用 Jetifier 标志

由于大多数项目直接使用 AndroidX 库,因此您可以删除 Jetifier 标志以获得更好的构建性能。要删除 Jetifier 标志,请在 gradle.properties 文件中设置 android.enableJetifier=false

构建分析器可以执行检查以查看是否可以安全地删除该标志,以使您的项目获得更好的构建性能并从未维护的 Android Support 库迁移。要了解有关构建分析器的更多信息,请参阅 解决构建性能问题

使用配置缓存

配置缓存 允许 Gradle 记录有关构建任务图的信息并在后续构建中重用它,因此 Gradle 不必再次重新配置整个构建。

要启用配置缓存,请执行以下步骤

  1. 检查所有项目插件是否兼容。

    使用 构建分析器 检查您的项目是否与配置缓存兼容。构建分析器运行一系列测试构建以确定是否可以为项目打开此功能。有关支持的插件列表,请参阅 问题 #13490

  2. 将以下代码添加到 gradle.properties 文件中

      org.gradle.configuration-cache=true
      # Use this flag carefully, in case some of the plugins are not fully compatible.
      org.gradle.configuration-cache.problems=warn

启用配置缓存后,第一次运行项目时,构建输出会显示 Calculating task graph as no configuration cache is available for tasks。在后续运行中,构建输出会显示 Reusing configuration cache

要了解有关配置缓存的更多信息,请参阅博文 配置缓存深度解析 和有关 配置缓存 的 Gradle 文档。

Gradle 8.1 和 Android Gradle 插件 8.1 中引入的配置缓存问题

配置缓存在 Gradle 8.1 中变得稳定,并引入了文件 API 跟踪。Gradle 会记录诸如 File.exists()File.isDirectory()File.list() 之类的调用以跟踪配置输入文件。

Android Gradle 插件 (AGP) 8.1 对 Gradle 不应视为缓存输入的一些文件使用了这些 File API。这会在与 Gradle 8.1 及更高版本一起使用时触发额外的缓存失效,从而降低构建性能。以下被视为 AGP 8.1 中的缓存输入

输入 问题跟踪器 在以下版本中修复
$GRADLE_USER_HOME/android/FakeDependency.jar 问题 #289232054 AGP 8.2
cmake 输出 问题 #287676077 AGP 8.2
$GRADLE_USER_HOME/.android/analytics.settings 问题 #278767328 AGP 8.3

如果您使用这些 API 或使用这些 API 的插件,您可能会遇到构建时间的回归,因为使用这些 API 的某些构建逻辑可能会触发额外的缓存失效。请参阅 构建配置输入跟踪的改进,了解这些模式以及如何修复构建逻辑,或暂时禁用文件 API 跟踪。