Phiên bản Java trong các bản dựng Android

Cho dù mã nguồn của bạn được viết bằng Java, Kotlin hay cả hai, vẫn có một số nơi bạn phải chọn một phiên bản ngôn ngữ JDK hoặc Java cho bản dựng.

Tổng quan về các mối quan hệ JDK trong bản dựng Gradle

Bảng chú giải thuật ngữ

Bộ công cụ phát triển Java (JDK)
Bộ phát triển Java (JDK) chứa:
  • Các công cụ như trình biên dịch, trình phân tích tài nguyên và trình tạo bản lưu trữ. Các tham số này được dùng trong hậu trường trong quá trình tạo bản dựng để tạo ứng dụng của bạn.
  • Các thư viện chứa API mà bạn có thể gọi từ mã nguồn Kotlin hoặc Java. Xin lưu ý rằng không phải chức năng nào cũng dùng được trên Android.
  • Máy ảo Java (JVM), một trình thông dịch thực thi các ứng dụng Java. Bạn sẽ sử dụng JVM để chạy IDE của Android Studio và công cụ xây dựng Gradle. JVM không được dùng trên các thiết bị Android hoặc trình mô phỏng.
Thời gian chạy JetBrains (JBR)
JetBrains Runtime (JBR) là một JDK nâng cao, được phân phối bằng Android Studio. Phiên bản này có một số tính năng tối ưu hoá để sử dụng trong Studio và các sản phẩm liên quan của JetBrains, nhưng cũng có thể dùng để chạy các ứng dụng Java khác.

Làm cách nào để chọn JDK để chạy Android Studio?

Bạn nên dùng JBR để chạy Android Studio. Thư viện này được triển khai cùng với và dùng để kiểm thử Android Studio, đồng thời bao gồm các tính năng nâng cao để sử dụng Android Studio tối ưu. Để đảm bảo điều này, đừng đặt biến môi trường STUDIO_JDK.

Các tập lệnh khởi động cho Android Studio sẽ tìm một JVM theo thứ tự sau:

  1. Biến môi trường STUDIO_JDK
  2. Thư mục studio.jdk (trong bản phân phối của Android Studio)
  3. Thư mục jbr (JetBrains Runtime), trong bản phân phối của Android Studio. Nên dùng.
  4. Biến môi trường JDK_HOME
  5. Biến môi trường JAVA_HOME
  6. java có thể thực thi trong biến môi trường PATH

Làm cách nào để chọn JDK nào chạy được các bản dựng Gradle?

Nếu bạn chạy Gradle bằng các nút trong Android Studio, thì JDK đặt trong các chế độ cài đặt Android Studio sẽ được dùng để chạy Gradle. Nếu bạn chạy Gradle trong một thiết bị đầu cuối, ở bên trong hay bên ngoài Android Studio, thì biến môi trường JAVA_HOME (nếu được đặt) sẽ xác định JDK nào chạy tập lệnh Gradle. Nếu bạn không đặt JAVA_HOME, lệnh này sẽ sử dụng lệnh java trên biến môi trường PATH.

Để có các kết quả nhất quán nhất, đừng quên đặt biến môi trường JAVA_HOMEcấu hình JDK của Gradle trong Android Studio thành cùng một JDK.

Khi chạy bản dựng, Gradle sẽ tạo một quy trình có tên là trình nền để thực hiện bản dựng thực tế. Bạn có thể sử dụng lại quy trình này, miễn là các bản dựng vẫn sử dụng cùng một phiên bản JDK và Gradle. Việc sử dụng lại một trình nền giúp giảm thời gian khởi động một JVM mới và khởi chạy hệ thống xây dựng.

Nếu bạn bắt đầu tạo bản dựng bằng nhiều phiên bản JDK hoặc Gradle, thì các trình nền bổ sung sẽ được tạo, tốn nhiều CPU và bộ nhớ hơn.

Cấu hình JDK của Gradle trong Android Studio

Để sửa đổi cấu hình JDK Gradle của dự án hiện có, hãy mở phần cài đặt Gradle trong phần File (hoặc Android Studio trên macOS) > Settings > Build, Execution, Deployment > Build Tools > Gradle (Tệp > Cài đặt > Thực thi, Triển khai > Công cụ xây dựng > Gradle). Trình đơn thả xuống Gradle JDK có các tuỳ chọn sau đây để bạn lựa chọn:

  • Các macro như JAVA_HOMEGRADLE_LOCAL_JAVA_HOME
  • Các mục nhập trong bảng JDK ở định dạng vendor-version như jbr-17 được lưu trữ trong Tệp cấu hình Android
  • Tải JDK xuống
  • Thêm một JDK cụ thể
  • Các JDK được phát hiện cục bộ từ thư mục cài đặt JDK mặc định của hệ điều hành

Tuỳ chọn đã chọn được lưu trữ trong tuỳ chọn gradleJvm thuộc tệp .idea/gradle.xml của dự án và độ phân giải đường dẫn JDK được dùng để chạy Gradle khi khởi động thông qua Android Studio.

Hình 1. Chế độ cài đặt JDK của Gradle trong Android Studio.

Các macro cho phép lựa chọn đường dẫn JDK của dự án động:

  • JAVA_HOME: sử dụng biến môi trường có cùng tên
  • GRADLE_LOCAL_JAVA_HOME: sử dụng thuộc tính java.home trong tệp .gradle/config.properties, mặc định là JetBrains Runtime.

JDK đã chọn được dùng để chạy bản dựng Gradle và phân giải các tệp tham chiếu API JDK khi chỉnh sửa tập lệnh và mã nguồn của bản dựng. Xin lưu ý rằng compileSdk được chỉ định sẽ hạn chế hơn nữa những biểu tượng Java có sẵn khi chỉnh sửa và tạo mã nguồn.

Hãy nhớ chọn phiên bản JDK cao hơn hoặc bằng với phiên bản JDK được dùng trong các trình bổ trợ mà bạn sử dụng trong bản dựng Gradle. Để xác định phiên bản JDK tối thiểu cần thiết cho Trình bổ trợ Android cho Gradle (AGP), hãy xem bảng khả năng tương thích trong ghi chú phát hành.

Ví dụ: Trình bổ trợ Android cho Gradle phiên bản 8.x yêu cầu JDK 17. Nếu bạn cố gắng chạy một bản dựng Gradle sử dụng bản dựng này với phiên bản JDK cũ hơn, thì bản dựng này sẽ báo cáo một thông báo như:

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`.

Tôi có thể sử dụng API Java nào trong mã nguồn Java hoặc Kotlin?

Ứng dụng Android có thể sử dụng một số API được xác định trong JDK, nhưng không phải tất cả. SDK Android xác định việc triển khai nhiều hàm thư viện Java như một phần của các API có sẵn. Thuộc tính compileSdk chỉ định phiên bản SDK Android sẽ sử dụng khi biên dịch mã nguồn Kotlin hoặc Java.

Kotlin

android {
    ...
    compileSdk = 33
}

Groovy

android {
    ...
    compileSdk 33
}

Mỗi phiên bản Android đều hỗ trợ một phiên bản JDK cụ thể và một tập hợp con các API Java có sẵn của JDK. Nếu dùng API Java có trong compileSdk không có trong minSdk được chỉ định, bạn có thể sử dụng API này trong phiên bản Android cũ thông qua quy trình đơn giản hoá. Xem các API Java 11 trở lên hiện có thông qua quá trình đơn giản hoá để biết các API được hỗ trợ.

Hãy dùng bảng này để xác định phiên bản Java được hỗ trợ bởi từng API Android và nơi để tìm thông tin chi tiết về những API Java hiện có.

Android Java Các tính năng API và ngôn ngữ được hỗ trợ
14 (API 34) 17 Thư viện Core
13 (API 33) 11 Thư viện Core
12 (API 32) 11 API Java
11 trở xuống Phiên bản Android

JDK nào biên dịch mã nguồn Java của tôi?

JDK chuỗi công cụ Java chứa trình biên dịch Java dùng để biên dịch mọi mã nguồn Java. JDK này cũng chạy javadoc và kiểm thử đơn vị trong quá trình tạo bản dựng.

Chuỗi công cụ mặc định là JDK dùng để chạy Gradle. Nếu bạn sử dụng giá trị mặc định và chạy một bản dựng trên nhiều máy (ví dụ: máy cục bộ và một máy chủ Tích hợp liên tục riêng biệt), thì kết quả của bản dựng có thể khác nhau nếu bạn sử dụng nhiều phiên bản JDK.

Để tạo một bản dựng nhất quán hơn, bạn có thể chỉ định rõ ràng một phiên bản chuỗi công cụ Java. Chỉ định điều này:

  • Tìm một JDK tương thích trên hệ thống đang chạy bản dựng.
    • Nếu không có JDK tương thích (và đã xác định trình phân giải chuỗi công cụ), hãy tải bản ghi xuống.
  • Hiển thị API Java chuỗi công cụ cho các lệnh gọi từ mã nguồn.
  • Biên dịch nguồn Java bằng phiên bản ngôn ngữ Java của nguồn đó.
  • Nguồn cung cấp mặc định cho sourceCompatibilitytargetCompatibility.

Trong mọi trường hợp, bạn nên chỉ định chuỗi công cụ Java và đảm bảo rằng bạn đã cài đặt JDK được chỉ định hoặc thêm trình phân giải chuỗi công cụ vào bản dựng.

Bạn có thể chỉ định chuỗi công cụ để xem mã nguồn của bạn được viết bằng Java, Kotlin hay cả hai. Hãy chỉ định chuỗi công cụ ở cấp cao nhất trong tệp build.gradle(.kts) trong mô-đun của bạn.

Nếu mã nguồn của bạn chỉ được viết bằng Java, hãy chỉ định phiên bản chuỗi công cụ Java như sau:

Kotlin

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

Groovy

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

Nếu nguồn của bạn chỉ là Kotlin hoặc kết hợp Kotlin và Java, hãy chỉ định phiên bản chuỗi công cụ Java như sau:

Kotlin

kotlin {
    jvmToolchain(17)
}

Groovy

kotlin {
    jvmToolchain 17
}

Phiên bản JDK của chuỗi công cụ có thể giống với JDK dùng để chạy Gradle, nhưng hãy lưu ý rằng chúng phục vụ các mục đích khác nhau.

Tôi có thể sử dụng các tính năng nguồn ngôn ngữ Java nào trong mã nguồn Java của mình?

Thuộc tính sourceCompatibility xác định tính năng ngôn ngữ Java nào có sẵn trong quá trình biên dịch nguồn Java. API này không ảnh hưởng đến nguồn Kotlin.

Nếu không được chỉ định, thì chế độ mặc định sẽ là chuỗi công cụ Java hoặc JDK dùng để chạy Gradle. Bạn nên chỉ định rõ ràng một chuỗi công cụ (ưu tiên) hoặc sourceCompatibility.

Chỉ định sourceCompatibility trong tệp build.gradle(.kts) của mô-đun.

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

Tôi có thể sử dụng các tính năng nhị phân nào của Java khi biên dịch nguồn Kotlin hoặc Java?

Việc chỉ định targetCompatibilityjvmTarget sẽ xác định phiên bản định dạng lớp Java tương ứng được dùng khi tạo mã byte cho nguồn Java và Kotlin được biên dịch.

Một số tính năng của Kotlin tồn tại trước khi các tính năng Java tương đương được thêm vào. Các trình biên dịch Kotlin ban đầu phải tạo ra cách riêng để thể hiện các tính năng Kotlin đó. Một số tính năng trong số này sau đó đã được thêm vào Java. Ở các cấp độ jvmTarget sau, trình biên dịch Kotlin có thể trực tiếp sử dụng tính năng Java, điều này có thể mang lại hiệu suất tốt hơn.

Theo mặc định, targetCompatibility sẽ có cùng một giá trị như sourceCompatibility, nhưng nếu được chỉ định, giá trị này phải lớn hơn hoặc bằng sourceCompatibility.

jvmTarget mặc định là phiên bản chuỗi công cụ.

Các phiên bản Android khác nhau sẽ hỗ trợ các phiên bản Java khác nhau. Bạn có thể tận dụng các tính năng bổ sung của Java bằng cách tăng targetCompatibilityjvmTarget. Tuy nhiên, điều này cũng có thể buộc bạn phải tăng phiên bản SDK Android tối thiểu để đảm bảo có thể sử dụng tính năng này.

Kotlin

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

Groovy

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