Android build 中的 Java 版本

无论您的源代码是使用 Java 和/或 Kotlin 编写的,都必须在多个地方为您的 build 选择 JDK 或 Java 语言版本。

Gradle build 中的 JDK 关系概览

术语库

Java 开发套件 (JDK)
Java 开发套件 (JDK) 包含:
  • 工具,例如编译器、性能分析器和归档创建工具。 它们会在构建期间在后台用于创建应用。
  • 包含可从 Kotlin 或 Java 源代码调用的 API 的库。请注意,并非所有函数在 Android 上都可用。
  • Java 虚拟机 (JVM),用于执行 Java 应用的解释器。您可以使用 JVM 运行 Android Studio IDE 和 Gradle 构建工具。JVM 不适用于 Android 设备或模拟器。
JetBrains 运行时 (JBR)
JetBrains 运行时 (JBR) 是一个增强的 JDK,通过 Android Studio 分发。 它包含多项可在 Studio 和相关 JetBrains 产品中使用的优化,但也可用于运行其他 Java 应用。

如何选择 JDK 来运行 Android Studio?

我们建议您使用 JBR 来运行 Android Studio。它与 Android Studio 一起部署并用于测试 Android Studio,其中包含用于实现 Android Studio 最佳使用情况的增强功能。为确保这一点,请勿设置 STUDIO_JDK 环境变量,

Android Studio 的启动脚本会按以下顺序查找 JVM:

  1. STUDIO_JDK 环境变量
  2. studio.jdk 目录(在 Android Studio 发行版中)
  3. jbr 目录(JetBrains 运行时)。推荐。
  4. JDK_HOME 环境变量
  5. JAVA_HOME 环境变量
  6. PATH 环境变量中的 java 可执行文件

如何选择运行 Gradle build 的 JDK?

如果您使用 Android Studio 中的按钮运行 Gradle,将使用 Android Studio 设置中设置的 JDK 运行 Gradle。如果您在终端(无论是 Android Studio 内部还是外部)运行 Gradle,JAVA_HOME 环境变量(如果已设置)决定了运行 Gradle 脚本的 JDK。如果未设置 JAVA_HOME,它会在 PATH 环境变量中使用 java 命令。

为了获得最一致的结果,请务必将 JAVA_HOME 环境变量和 Android Studio 中的 Gradle JDK 配置设为同一个 JDK。

运行 build 时,Gradle 会创建一个名为“守护程序”的进程来执行实际构建。只要 build 使用相同的 JDK 和 Gradle 版本,此过程就可以重复使用。重复使用守护程序可缩短启动新 JVM 和初始化构建系统的时间。

如果您使用不同的 JDK 或 Gradle 版本启动 build,则会创建其他守护程序,这会消耗更多的 CPU 和内存。

Android Studio 中的 Gradle JDK 配置

如需修改现有项目的 Gradle JDK 配置,请依次点击 FileAndroid Studio(在 macOS 上,依次点击 > Settings > Build, Execution, Deployment > Build Tools > Gradle)打开 Gradle 设置。Gradle JDK 下拉列表包含以下选项:

  • JAVA_HOMEGRADLE_LOCAL_JAVA_HOME 等宏
  • vendor-version 格式的 JDK 表条目(如 jbr-17),存储在 Android 配置文件
  • 下载 JDK
  • 添加特定的 JDK
  • 从操作系统的默认 JDK 安装目录中本地检测到的 JDK

所选选项存储在项目 .idea/gradle.xml 文件的 gradleJvm 选项中,其 JDK 路径解析用于通过 Android Studio 启动 Gradle。

图 1. Android Studio 中的 Gradle JDK 设置。

这些宏用于启用动态项目 JDK 路径选择:

  • JAVA_HOME:使用具有相同名称的环境变量
  • GRADLE_LOCAL_JAVA_HOME:使用 .gradle/config.properties 文件中的 java.home 属性,该属性默认为 JetBrains 运行时。

选定的 JDK 用于运行 Gradle build,并在修改 build 脚本和源代码时解析 JDK API 引用。请注意,指定的 compileSdk 会进一步限制在修改和构建源代码时可以使用的 Java 符号。

确保选择的 JDK 版本高于或等于您在 Gradle build 中使用的插件使用的 JDK 版本。如需确定 Android Gradle 插件 (AGP) 所需的最低 JDK 版本,请参阅版本说明中的兼容性表。

例如,Android Gradle 插件版本 8.x 需要 JDK 17。 如果您尝试运行将 Gradle build 与较低版本的 JDK 配合使用的 Gradle build,它会报告如下消息:

An exception occurred applying plugin request [id: 'com.android.application']
> Failed to apply plugin 'com.android.internal.application'.
   > Android Gradle plugin requires Java 17 to run. You are currently using Java 11.
      Your current JDK is located in /usr/local/buildtools/java/jdk11
      You can try some of the following options:
       - changing the IDE settings.
       - changing the JAVA_HOME environment variable.
       - changing `org.gradle.java.home` in `gradle.properties`.

我可以在 Java 或 Kotlin 源代码中使用哪些 Java API?

Android 应用可以使用 JDK 中定义的部分 API,但不能使用全部 API。Android SDK 将许多 Java 库函数的实现定义为其可用 API 的一部分。compileSdk 属性指定在编译 Kotlin 或 Java 源代码时要使用的 Android SDK 版本。

Kotlin

android {
    ...
    compileSdk = 33
}

Groovy

android {
    ...
    compileSdk 33
}

每个 Android 版本都支持特定版本的 JDK 及其可用 Java API 的子集。如果您使用的 Java API 在 compileSdk 中可用,而该 API 在指定的 minSdk 中不可用,您或许可以通过一个称为脱糖的过程在早期版本的 Android 中使用该 API。如需了解受支持的 API,请参阅通过脱糖提供的 Java 11 及更高版本 API

您可以根据下表确定每个 Android API 支持的 Java 版本,以及在何处查找可用的 Java API 的详细信息。

Android Java 支持的 API 和语言功能
14 (API 34) 17 核心库
13 (API 33) 11 核心库
12 (API 32) 11 Java API
11 及更低版本 Android 版本

哪个 JDK 可编译我的 Java 源代码?

Java 工具链 JDK 包含用于编译任何 Java 源代码的 Java 编译器。此 JDK 还会在构建期间运行 javadoc 和单元测试。

工具链默认使用用于运行 Gradle 的 JDK。如果您使用默认设置,并在不同的机器(例如,本地机器和单独的持续集成服务器)上运行构建,则使用不同的 JDK 版本时,构建结果可能会有所不同。

如需创建更加一致的构建,您可以明确指定 Java 工具链版本。指定此项:

  • 在运行 build 的系统中查找兼容的 JDK。
    • 如果不存在兼容的 JDK(并且定义了工具链解析器),则下载一个。
  • 公开用于从源代码进行调用的工具链 Java API。
  • 使用 Java 语言版本编译 Java 源代码。
  • sourceCompatibilitytargetCompatibility 提供默认值。

我们建议您始终指定 Java 工具链,并确保已安装指定的 JDK,或向 build 添加工具链解析器

您可以指定工具链,确保源代码是使用 Java 和/或 Kotlin 编写的。在模块的 build.gradle(.kts) 文件顶层指定工具链。

如果您的源代码只用 Java 编写,请按如下方式指定 Java 工具链版本:

Kotlin

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}

Groovy

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

如果您的源代码只有 Kotlin 或 Kotlin 和 Java 的混合版本,请按如下方式指定 Java 工具链版本:

Kotlin

kotlin {
    jvmToolchain(17)
}

Groovy

kotlin {
    jvmToolchain 17
}

工具链 JDK 版本可以与用于运行 Gradle 的 JDK 版本相同,但请注意,它们的用途不同。

我可以在 Java 源代码中使用哪些 Java 语言源功能?

sourceCompatibility 属性决定了在编译 Java 源代码期间可以使用哪些 Java 语言功能。而不会影响 Kotlin 源代码。

如果未指定,则默认为用于运行 Gradle 的 Java 工具链或 JDK。我们建议您始终明确指定工具链(首选)或 sourceCompatibility

在模块的 build.gradle(.kts) 文件中指定 sourceCompatibility

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

编译 Kotlin 或 Java 源代码时,可以使用哪些 Java 二进制功能?

指定 targetCompatibilityjvmTarget 可分别确定为已编译的 Java 和 Kotlin 源代码生成字节码时使用的 Java 类格式版本。

某些 Kotlin 功能在添加等效的 Java 功能之前就已经存在。早期的 Kotlin 编译器必须创建自己的方法来表示这些 Kotlin 功能。其中一些功能后来被添加到 Java 中。使用较新的 jvmTarget 级别时,Kotlin 编译器可能会直接使用 Java 功能,这可能会带来更好的性能。

targetCompatibility 默认为与 sourceCompatibility 相同的值,但如果指定,则必须大于或等于 sourceCompatibility

jvmTarget 默认为工具链版本。

不同版本的 Android 支持不同版本的 Java。您可以通过增加 targetCompatibilityjvmTarget 来利用其他 Java 功能,但这可能会迫使您同时提高最低 Android SDK 版本以确保该功能可用。

Kotlin

android {
    compileOptions {
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
}

Groovy

android {
    compileOptions {
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget '17'
    }
}