优化构建速度

漫长的构建时间会减慢您的开发进程。本页面提供了一些技术,可帮助解决构建速度瓶颈。

提高应用构建速度的一般过程如下:

  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 插件门户放在最后

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

Gradle 会按照声明顺序搜索仓库,因此如果首先列出的仓库包含大部分插件,则可以提高构建性能。因此,尝试将 gradlePluginPortal() 条目放在 settings.gradle 文件中的仓库块的最后。在大多数情况下,这会最大限度地减少冗余插件搜索的数量并提高构建速度。

有关 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 库模块的代码。以这种方式模块化代码允许构建系统仅编译您修改的模块,并缓存这些输出以供将来构建。当您启用并行项目执行优化时,模块化还可以使并行项目执行更有效。

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

在您创建构建配置文件后,如果构建配置文件显示相当一部分构建时间花费在 Configuring Projects 阶段,请检查您的 build.gradle 脚本,并寻找可包含在自定义 Gradle 任务中的代码。通过将一些构建逻辑移入任务,您可以帮助确保任务仅在需要时运行,结果可以为后续构建缓存,并且如果启用并行项目执行,构建逻辑将有资格并行运行。要了解有关自定义构建逻辑任务的更多信息,请阅读官方 Gradle 文档

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

将图片转换为 WebP

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

减少图片文件大小而无需执行构建时压缩可以加快您的构建速度,特别是如果您的应用使用了大量图片资源。但是,在解压缩 WebP 图片时,您可能会注意到设备 CPU 使用率略有增加。使用 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 创建的项目,请通过依次点击 Refactor > Migrate to Non-Transitive R Classes 来更新它们以使用非传递性 R 类。

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

使用非常量 R 类

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

禁用 Jetifier 标志

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

构建分析器可以执行检查,以确定是否可以安全地移除该标志,从而使您的项目具有更好的构建性能并从不再维护的 Android 支持库迁移。要了解有关构建分析器的更多信息,请参阅排查构建性能问题

使用配置缓存

配置文件配置缓存允许 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 跟踪功能。诸如 File.exists()File.isDirectory()File.list() 等调用由 Gradle 记录,以跟踪配置输入文件。

Android Gradle 插件 (AGP) 8.1 对某些文件使用了这些 File API,而 Gradle 不应将这些文件视为缓存输入。这在与 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 跟踪,请参阅构建配置输入跟踪的改进