Android 建構作業中的 Java 版本

無論原始碼是以 Java 和/或 Kotlin 編寫,還是在幾個地方,您都必須選擇 JDK 或 Java 語言版本進行建構。

Gradle 建構作業中的 JDK 關係總覽

詞彙解釋

Java Development Kit (JDK)
Java Development Kit (JDK) 包含:
  • 包括編譯器、分析器和封存建立者等工具。在建構期間,系統會使用這些資訊建立應用程式。
  • 包含 API 的程式庫,可透過 Kotlin 或 Java 原始碼呼叫。請注意,並非所有函式都適用於 Android。
  • Java 虛擬機器 (JVM) 是執行 Java 應用程式的解譯器。您可使用 JVM 執行 Android Studio IDE 和 Gradle 建構工具。Android 裝置或模擬器上並未使用 JVM。
JetBrains 執行階段 (JBR)
JetBrains Runtime (JBR) 是藉由 Android Studio 發布的強化版 JDK。其中包含多項最佳化功能,以便用於 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 執行檔

如何選擇哪些 JDK 來執行 Gradle 建構作業?

如果您使用 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。

執行建構作業時,Gradle 會建立名為 daemon 的程序,用於執行實際建構作業。只要建構版本使用相同的 JDK 和 Gradle 版本,您就可以重複使用這項程序。重複使用 Daemon 可以減少啟動新 JVM 並初始化建構系統的時間。

如果您使用不同的 JDK 或 Gradle 版本開始建構,系統會建立額外的 Daemon,消耗更多 CPU 和記憶體。

Android Studio 中的 Gradle JDK 設定

如要修改現有專案的 Gradle JDK 設定,請透過「File」 (或在 macOS 為「Android Studio」) 開啟 Gradle 設定,然後依序點選「Settings」>「Build, Execution, Deployment」>「Build Tools」>「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 時用於執行 Gradle。

圖 1:Android Studio 中的 Gradle JDK 設定。

巨集可啟用動態專案的 JDK 路徑選項:

  • JAVA_HOME:使用同名的環境變數
  • GRADLE_LOCAL_JAVA_HOME:使用 .gradle/config.properties 檔案中的 java.home 屬性,該屬性預設為 JetBrains 執行階段。

編輯建構指令碼和原始碼時,系統會使用選定的 JDK 執行 Gradle 建構作業,並解析 JDK API 參照。請注意,指定的 compileSdk 會進一步限制編輯及建構原始碼時可用的 Java 符號。

請務必選擇高於或等於 Gradle 建構作業中外掛程式使用的 JDK 版本。如要判斷 Android Gradle 外掛程式 (AGP) 的最低 JDK 版本,請參閱「版本資訊」中的相容性表格。

舉例來說,Android Gradle 外掛程式 8.x 版需要 JDK 17。如果您嘗試執行 Gradle 版本搭配舊版 JDK 版本,則系統會回報以下訊息:

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 不適用於指定的 minSdk,但 compileSdk 未提供此 API,則您或許可以透過「脫糖」程序,在舊版 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 工具鍊版本。指定:

  • 在執行版本的系統上找出相容的 JDK。
    • 如果沒有相容的 JDK (且已定義工具鍊解析器),請下載一個。
  • 公開工具鍊 Java API,以便從原始碼呼叫。
  • 使用 Java 語言版本編譯 Java 原始碼。
  • sourceCompatibilitytargetCompatibility 提供預設值。

建議您一律指定 Java 工具鍊,並確認已安裝指定的 JDK,或是在版本中新增工具鍊解析器

您可以指定工具鍊,指定原始碼是以 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 類別格式版本。

在新增同等 Java 功能前就已經存在部分 Kotlin 功能。早期的 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'
    }
}