Wersje Javy w kompilacji Androida

Niezależnie od tego, czy kod źródłowy jest napisany w języku Java, Kotlin czy w obu tych językach, musisz wybrać JDK lub wersję języka Java dla kompilacji w kilku miejscach.

Omówienie relacji JDK w kompilacji Gradle
Rysunek 1. Zależności JDK w kompilacji

Słowniczek

Java Development Kit (JDK)
Java Development Kit (JDK) zawiera:
  • narzędzia, takie jak kompilator, profiler i twórca archiwum; Są one używane za kulisami podczas kompilacji do utworzenia aplikacji.
  • Biblioteki zawierające interfejsy API, które można wywoływać z kodu źródłowego w języku Kotlin lub Java. Pamiętaj, że nie wszystkie funkcje są dostępne na Androidzie.
  • Maszyna wirtualna Java (JVM) – interpreter, który wykonuje aplikacje Java. JVM służy do uruchamiania IDE Android Studio i narzędzia do kompilacji Gradle. JVM nie jest używana na urządzeniach z Androidem ani na emulatorach.
JetBrains Runtime (JBR)
JetBrains Runtime (JBR) to ulepszony pakiet JDK, który jest rozpowszechniany razem z Android Studio. Zawiera kilka optymalizacji do użytku w Studio i powiązanych usługach JetBrains, ale można go też używać do uruchamiania innych aplikacji Java.

Jak wybrać pakiet JDK do uruchamiania Android Studio?

Zalecamy używanie JBR do uruchamiania Android Studio. Jest wdrażany i używany do testowania Android Studio oraz zawiera ulepszenia zapewniające optymalne korzystanie z Android Studio. Aby to zapewnić, nie ustawiaj zmiennej środowiskowej STUDIO_JDK.

Skrypty startowe Android Studio szukają maszyny JVM w tej kolejności:

  1. Zmienna środowiskowa STUDIO_JDK
  2. Katalog studio.jdk (w dystrybucji Android Studio)
  3. Katalog jbr (JetBrains Runtime) w dystrybucji Android Studio. Zalecane.
  4. Zmienna środowiskowa JDK_HOME
  5. Zmienna środowiskowa JAVA_HOME
  6. Plik wykonywalny java w zmiennej środowiskowej PATH

Jak wybrać pakiet JDK, który ma uruchamiać kompilacje Gradle?

Jeśli uruchamiasz Gradle za pomocą przycisków w Android Studio, do uruchomienia Gradle jest używany pakiet JDK ustawiony w ustawieniach Android Studio. Jeśli uruchamiasz Gradle w terminalu w Android Studio lub poza nim, zmienna środowiskowa JAVA_HOME (jeśli jest ustawiona) określa, który pakiet JDK uruchamia skrypty Gradle. Jeśli zmienna JAVA_HOME nie jest ustawiona, używane jest polecenie java w zmiennej środowiskowej PATH.

Aby uzyskać najbardziej spójne wyniki, ustaw zmienną środowiskową JAVA_HOME i konfigurację Gradle JDK w Android Studio na ten sam pakiet JDK.

Podczas kompilacji Gradle tworzy proces o nazwie demon, który wykonuje rzeczywistą kompilację. Ten proces można wykorzystać ponownie, o ile kompilacje używają tej samej wersji JDK i Gradle. Ponowne użycie demona skraca czas potrzebny na uruchomienie nowej maszyny JVM i zainicjowanie systemu kompilacji.

Jeśli uruchomisz kompilacje z różnymi wersjami JDK lub Gradle, zostaną utworzone dodatkowe demony, które będą zużywać więcej procesora i pamięci.

Konfiguracja Gradle JDK w Android Studio

Aby zmodyfikować konfigurację Gradle JDK w istniejącym projekcie, otwórz ustawienia Gradle, klikając Plik (lub Android Studio w systemie macOS) > Ustawienia > Kompilacja, wykonanie, wdrożenie > Narzędzia do kompilacji > Gradle. Menu Gradle JDK zawiera te opcje:

  • makra takie jak JAVA_HOME i GRADLE_LOCAL_JAVA_HOME;
  • Wpisy w tabeli JDK w formacie vendor-version, np. jbr-17, które są przechowywane w plikach konfiguracji Androida.
  • Pobieranie JDK
  • Dodawanie konkretnego pakietu JDK
  • Lokalnie wykryte pakiety JDK z domyślnego katalogu instalacyjnego JDK systemu operacyjnego

Wybrana opcja jest przechowywana w opcji gradleJvm w pliku .idea/gradle.xml projektu, a rozpoznawanie ścieżki JDK jest używane do uruchamiania Gradle po uruchomieniu w Android Studio.

Rysunek 2. Ustawienia JDK Gradle w Android Studio.

Makra umożliwiają dynamiczny wybór ścieżki JDK projektu:

  • JAVA_HOME: używa zmiennej środowiskowej o tej samej nazwie.
  • GRADLE_LOCAL_JAVA_HOME: używa właściwości java.home w pliku .gradle/config.properties, która domyślnie wskazuje na JetBrains Runtime.

Wybrany pakiet JDK jest używany do uruchamiania kompilacji Gradle i rozwiązywania odwołań do interfejsu API JDK podczas edytowania skryptów kompilacji i kodu źródłowego. Pamiętaj, że określony compileSdk dodatkowo ograniczy symbole Java, które będą dostępne podczas edytowania i kompilowania kodu źródłowego.

Wybierz wersję JDK, która jest wyższa lub równa wersji JDK używanej przez wtyczki, których używasz w kompilacji Gradle. Aby określić minimalną wymaganą wersję JDK dla wtyczki Androida do obsługi Gradle (AGP), zapoznaj się z tabelą zgodności w informacjach o wersji.

Na przykład wtyczka Androida do obsługi Gradle w wersji 8.x wymaga pakietu JDK 17. Jeśli spróbujesz uruchomić kompilację Gradle, która używa tej wtyczki, z wcześniejszą wersją pakietu JDK, pojawi się komunikat podobny do tego:

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

Których interfejsów API Javy mogę używać w kodzie źródłowym Javy lub Kotlina?

Aplikacja na Androida może używać niektórych interfejsów API zdefiniowanych w JDK, ale nie wszystkich. Android SDK definiuje implementacje wielu funkcji biblioteki Java w ramach dostępnych interfejsów API. Właściwość compileSdk określa, której wersji pakietu Android SDK używać podczas kompilowania kodu źródłowego Kotlin lub Java.

Kotlin

android {
    ...
    compileSdk = 36
}

Dynamiczny

android {
    ...
    compileSdk 36
}

Każda wersja Androida obsługuje określoną wersję JDK i podzbiór dostępnych interfejsów API Javy. Jeśli używasz interfejsu Java API, który jest dostępny w compileSdk, ale nie w określonym minSdk, możesz użyć tego interfejsu API we wcześniejszej wersji Androida w ramach procesu zwanego odlukrzaniem. Obsługiwane interfejsy API znajdziesz w artykule Interfejsy API Javy 11+ dostępne dzięki odlukrzaniu.

Z tej tabeli dowiesz się, która wersja Javy jest obsługiwana przez poszczególne interfejsy API Androida i gdzie znaleźć szczegółowe informacje o dostępnych interfejsach API Javy.

Android Java Obsługiwane funkcje interfejsu API i języka
14 (API 34) 17 Biblioteki podstawowe
13 (API 33) 11 Biblioteki podstawowe
12 (API 32) 11 Java API
11 lub starsza Wersje Androida

Który pakiet JDK kompiluje mój kod źródłowy w języku Java?

Łańcuch narzędzi Java JDK zawiera kompilator Java używany do kompilowania kodu źródłowego Java. Ten pakiet JDK uruchamia też javadoc i testy jednostkowe podczas kompilacji.

Domyślny łańcuch narzędzi to JDK używany do uruchamiania Gradle. Jeśli użyjesz ustawienia domyślnego i uruchomisz kompilację na różnych maszynach (np. na maszynie lokalnej i oddzielnym serwerze trybu ciągłej integracji), wyniki kompilacji mogą się różnić, jeśli używane są różne wersje JDK.

Aby utworzyć bardziej spójną kompilację, możesz wyraźnie określić wersję zestawu narzędzi Java. Jeśli określisz:

  • znajduje zgodny pakiet JDK w systemie, w którym jest uruchamiana kompilacja;
    • Jeśli nie ma zgodnego pakietu JDK (i zdefiniowano mechanizm rozpoznawania zestawu narzędzi), pobiera go.
  • Udostępnia interfejsy API Java zestawu narzędzi na potrzeby wywołań z kodu źródłowego.
  • Kompiluje źródło Java przy użyciu wersji języka Java.
  • Dostarcza wartości domyślne dla sourceCompatibility i targetCompatibility.

Zalecamy, aby zawsze określać łańcuch narzędzi Java i upewnić się, że określony pakiet JDK jest zainstalowany, lub dodać do kompilacji resolver łańcucha narzędzi.

Możesz określić zestaw narzędzi niezależnie od tego, czy kod źródłowy jest napisany w języku Java, Kotlin czy w obu tych językach. Określ łańcuch narzędzi na najwyższym poziomie pliku build.gradle(.kts) modułu.

Określ wersję zestawu narzędzi Java w ten sposób:

Kotlin

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

Dynamiczny

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

Działa to, jeśli źródłem jest Kotlin, Java lub kombinacja obu tych języków.

Wersja JDK zestawu narzędzi może być taka sama jak wersja JDK używana do uruchamiania Gradle, ale pamiętaj, że służą one do różnych celów.

Których funkcji źródłowych języka Java mogę używać w kodzie źródłowym Java?

Właściwość sourceCompatibility określa, które funkcje języka Java są dostępne podczas kompilacji kodu źródłowego Java. Nie ma to wpływu na źródło Kotlin.

Określ sourceCompatibility w pliku build.gradle(.kts) modułu w ten sposób:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Dynamiczny

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

Jeśli nie podasz żadnej wartości, domyślnie zostanie użyta wersja łańcucha narzędzi Java. Jeśli nie używasz łańcucha narzędzi Java, domyślnie używana jest wersja wybrana przez wtyczkę Androida do obsługi Gradle (np. Java 8 lub nowsza).

Których funkcji binarnych Javy można używać podczas kompilowania kodu źródłowego Kotlina lub Javy?

Właściwość targetCompatibility określa wersję formatu klasy Java używaną podczas generowania kodu bajtowego dla skompilowanego kodu źródłowego Java i Kotlin.

Niektóre funkcje Kotlina istniały, zanim dodano ich odpowiedniki w Javie. Wczesne kompilatory Kotlina musiały tworzyć własne sposoby reprezentowania tych funkcji Kotlina. Niektóre z tych funkcji zostały później dodane do Javy. W przypadku wyższych poziomów targetCompatibility kompilator Kotlina może bezpośrednio używać funkcji Javy, co może zwiększyć wydajność.

Różne wersje Androida obsługują różne wersje Javy. Możesz korzystać z dodatkowych funkcji Javy, zwiększając targetCompatibility, ale może to wymagać zwiększenia minimalnej wersji pakietu Android SDK, aby funkcja była dostępna.

Pamiętaj, że wartość targetCompatibility musi być większa lub równa sourceCompatibility. W praktyce parametry sourceCompatibility i targetCompatibility powinny mieć tę samą wartość. Możesz je ustawić w ten sposób:

Kotlin

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

Dynamiczny

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

Jeśli używasz wersji Kotlina starszej niż 2.2, musisz też ustawić kotlinOptions:

Kotlin

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

Dynamiczny

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

Jeśli nie zostaną określone, domyślnie używana jest wersja łańcucha narzędzi Java. Jeśli nie używasz łańcucha narzędzi Java, wartości domyślne mogą się różnić i powodować problemy z kompilacją. Dlatego zalecamy, aby zawsze wyraźnie określać te wartości lub używać łańcucha narzędzi Java.