Android 建構作業中的 Java 版本

無論原始碼是以 Java、Kotlin 或兩者編寫,您都必須在多個位置選擇建構作業的 JDK 或 Java 語言版本。

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

詞彙

Java Development Kit (JDK)
Java Development Kit (JDK) 包含:
  • 編譯器、分析器和封存建立工具等。 系統會在建構期間於背景使用這些項目,建立應用程式。
  • 程式庫包含可從 Kotlin 或 Java 原始碼呼叫的 API。請注意,並非所有函式都適用於 Android。
  • Java 虛擬機器 (JVM),這是一種執行 Java 應用程式的解譯器。您可以使用 JVM 執行 Android Studio IDE 和 Gradle 建構工具。Android 裝置或模擬器不會使用 JVM。
JetBrains Runtime (JBR)
JetBrains Runtime (JBR) 是 Android Studio 隨附的強化版 JDK。其中包含多項最佳化功能,可在 Studio 和相關 JetBrains 產品中使用,但也可以用來執行其他 Java 應用程式。

如何選擇要用於執行 Android Studio 的 JDK?

建議您使用 JBR 執行 Android Studio。它與 Android Studio 一起部署並用於測試 Android Studio,並包含最佳化 Android Studio 使用的增強功能。為確保這一點,請勿設定 STUDIO_JDK 環境變數。

Android Studio 的開機指令碼會依下列順序尋找 JVM:

  1. STUDIO_JDK 環境變數
  2. studio.jdk 目錄 (位於 Android Studio 發行版中)
  3. Android Studio 發行版中的 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」) >「Settings」>「Build, Execution, Deployment」>「Build Tools」>「Gradle」,開啟 Gradle 設定。「Gradle JDK」下拉式選單包含下列選項:

  • JAVA_HOME 和 GRADLE_LOCAL_JAVA_HOME 等巨集
  • vendor-version 格式的 JDK 表格項目 (例如 jbr-17),儲存在 Android 設定檔中
  • 下載 JDK
  • 新增特定 JDK
  • 從作業系統預設 JDK 安裝目錄中,在本機偵測到的 JDK

所選選項會儲存在專案 .idea/gradle.xml 檔案的 gradleJvm 選項中,且透過 Android Studio 啟動時,系統會使用其 JDK 路徑解析執行 Gradle。

圖 2 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 版本的 JDK 版本。如要判斷 Android Gradle 外掛程式 (AGP) 所需的最低 JDK 版本,請參閱版本資訊中的相容性表格。

舉例來說,Android Gradle 外掛程式 8.x 版需要 JDK 17。如果您嘗試使用舊版 JDK 執行 Gradle 建構作業,系統會顯示類似以下訊息:

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/jdk
      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,但並非全部。Android SDK 定義了許多 Java 程式庫函式的實作,做為可用 API 的一部分。compileSdk 屬性會指定編譯 Kotlin 或 Java 原始碼時要使用的 Android SDK 版本。

Kotlin

android {
    ...
    compileSdk = 36
}

Groovy

android {
    ...
    compileSdk 36
}

每個 Android 版本都支援特定版本的 JDK,以及部分可用的 Java API。如果您使用的 Java API 適用於 compileSdk,但不適用於指定的 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 工具鍊版本。指定這項屬性:

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

建議您一律指定 Java 工具鍊,並確保已安裝指定的 JDK,或在建構作業中新增工具鍊解析器。

無論原始碼是以 Java、Kotlin 或兩者編寫,您都可以指定工具鍊。在模組 build.gradle(.kts) 檔案的頂層指定工具鍊。

請按照下列方式指定 Java 工具鍊版本:

Kotlin

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

Groovy

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

無論來源是 Kotlin、Java 或兩者混合,都適用這個方法。

工具鍊 JDK 版本可以與執行 Gradle 所用的 JDK 相同,但請注意,兩者的用途不同。

我可以在 Java 原始碼中使用哪些 Java 語言來源功能?

sourceCompatibility 屬性會決定編譯 Java 原始碼時可用的 Java 語言功能。不會影響 Kotlin 來源。

在模組的 build.gradle(.kts) 檔案中指定 sourceCompatibility,如下所示:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

如未指定,這項屬性會預設為 Java 工具鍊版本。如果您未使用 Java 工具鍊,則會預設為 Android Gradle 外掛程式選擇的版本 (例如 Java 8 以上版本)。

編譯 Kotlin 或 Java 原始碼時,可以使用哪些 Java 二進位檔功能?

targetCompatibility 屬性會決定為已編譯的 Java 和 Kotlin 來源產生位元碼時,分別使用的 Java 類別格式版本。

部分 Kotlin 功能在對應的 Java 功能新增前就已存在。早期的 Kotlin 編譯器必須自行建立方法來表示這些 Kotlin 功能。其中部分功能後來也加入 Java。 在較高的 targetCompatibility 級別中,Kotlin 編譯器可能會直接使用 Java 功能,進而提升效能。

不同版本的 Android 支援不同版本的 Java。您可以提高 targetCompatibility,以便使用其他 Java 功能,但這可能也會迫使您提高 Android SDK 最低版本,以確保該功能可用。

請注意,targetCompatibility 必須大於或等於 sourceCompatibility。在實際操作中,sourceCompatibility 和 targetCompatibility 通常應使用相同的值。設定方式如下:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}

如果您使用的 Kotlin 版本低於 2.2,則還需要設定 kotlinOptions:

Kotlin

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

Groovy

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

如未指定,這些屬性會預設為 Java 工具鍊版本。如果您未使用 Java 工具鍊,預設值可能會有所不同,並導致建構問題。因此,建議您一律明確指定這些值,或使用 Java 工具鍊。