Wersje Javy w kompilacjach Androida

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

Omówienie relacji JDK w kompilacji Gradle

Słowniczek

Pakiet Java Development Kit (JDK)
Pakiet Java Development Kit (JDK) zawiera:
  • Narzędzia takie jak kompilator, program profilujący i kreator archiwów. Są one używane za kulisami podczas kompilacji przy tworzeniu 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.
  • Wirtualna maszyna wirtualna Java (JVM) to interpreter wykonujący aplikacje w Javie. Służy do uruchamiania środowiska IDE Android Studio i narzędzia do kompilacji Gradle za pomocą JVM. JVM nie jest używane na urządzeniach z Androidem ani w emulatorach.
Środowisko wykonawcze JetBrains (JBR)
JetBrains Runtime (JBR) to ulepszony pakiet JDK rozpowszechniany w Android Studio. Zawiera kilka optymalizacji do wykorzystania w Studio i powiązanych usługach JetBrains, ale może też służyć do uruchamiania innych aplikacji w Javie.

Jak wybrać pakiet JDK, aby uruchomić Android Studio?

Do uruchamiania Android Studio zalecamy używanie pakietu JBR. Jest wdrażany w Android Studio i używany do testowania. Zawiera też ulepszenia zapewniające optymalne wykorzystanie Android Studio. Aby to zagwarantować, nie ustawiaj zmiennej środowiskowej STUDIO_JDK.

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

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

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

Jeśli uruchomisz Gradle za pomocą przycisków w Android Studio, do uruchomienia Gradle będzie używany pakiet JDK określony w ustawieniach Android Studio. Jeśli uruchomisz Gradle w terminalu, zarówno w Android Studio, jak i poza nim, zmienna środowiskowa JAVA_HOME (jeśli jest ustawiona) określa, który pakiet JDK uruchamia skrypty Gradle. Jeśli zasada JAVA_HOME nie jest ustawiona, używa polecenia java w zmiennej środowiskowej PATH.

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

Podczas uruchamiania kompilacji Gradle tworzy proces nazywany demonem, aby wykonać kompilację. Tego procesu można użyć ponownie, jeśli kompilacje korzystają z tej samej wersji JDK i Gradle. Ponowne użycie demona skraca czas uruchamiania nowego JVM i zainicjowania systemu kompilacji.

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

Konfiguracja pakietu JDK Gradle w Android Studio

Aby zmienić konfigurację Gradle JDK istniejącego projektu, otwórz ustawienia Gradle, wybierając Plik (lub Android Studio w systemie macOS) > Ustawienia > Kompilacja, wykonanie, Wdrażanie > Narzędzia do kompilacji > Gradle. W menu Gradle JDK znajdziesz te opcje do wyboru:

  • Makra takie jak JAVA_HOME i GRADLE_LOCAL_JAVA_HOME
  • Wpisy tabeli JDK w formacie vendor-version, takim jak jbr-17, które są przechowywane w plikach konfiguracji Androida
  • Pobieranie pakietu JDK
  • Dodawanie określonego pliku JDK
  • Wykryte lokalnie pakiety JDK z domyślnego katalogu instalacyjnego JDK systemu operacyjnego

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

Rysunek 1. Ustawienia pakietu 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. Domyślnie jest to środowisko wykonawcze JetBrains.

Wybrany pakiet JDK jest używany do uruchamiania kompilacji Gradle i rozwiązywania odwołań do interfejsu JDK API podczas edytowania skryptów kompilacji i kodu źródłowego. Pamiętaj, że podana właściwość compileSdk dodatkowo ogranicza, które symbole Java 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żywanych przez wtyczki używane w kompilacji Gradle. Aby określić minimalną 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 jej ze starszą wersją 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/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`.

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

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

Kotlin

android {
    ...
    compileSdk = 33
}

Odlotowy

android {
    ...
    compileSdk 33
}

Każda wersja Androida obsługuje konkretną wersję pakietu JDK i podzbiór dostępnych interfejsów API Java. Jeśli używasz interfejsu API w języku Java, który jest dostępny w compileSdk, który nie jest dostępny w podanym obiekcie minSdk, możesz spróbować użyć tego interfejsu w starszej wersji Androida w ramach procesu zwanego wycofywaniem. Obsługiwane interfejsy API znajdziesz na stronie Interfejsy API Java w wersji 11 i nowszych dostępne po odwyczajaniu.

Z tej tabeli dowiesz się, która wersja Javy jest obsługiwana przez każdy interfejs API na Androida i gdzie znaleźć szczegółowe informacje o dostępnych interfejsach Java API.

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 Interfejs API Java
11 i starsze Wersje Androida

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

JDK łańcuch narzędzi Java zawiera kompilator Java służący do kompilowania dowolnego kodu źródłowego Java. Ten pakiet JDK uruchamia również testy javadoc i jednostkowe podczas kompilacji.

Domyślnym interfejsem pęku narzędzi jest pakiet JDK używany do uruchamiania Gradle. Jeśli używasz wersji domyślnej i uruchomisz kompilację na różnych komputerach (np. na komputerze lokalnym i osobnym serwerze do ciągłej integracji), wyniki kompilacji mogą się różnić, jeśli używane będą różne wersje JDK.

Aby utworzyć bardziej spójną kompilację, możesz bezpośrednio określić wersję łańcucha narzędzi Java. Określenie:

  • Znajduje zgodny pakiet JDK w systemie, w którym jest uruchomiona kompilacja.
    • Jeśli nie istnieje zgodny pakiet JDK (i jest zdefiniowany program do rozpoznawania łańcucha narzędzi), jest on pobierany.
  • Udostępnia interfejsy API w Javie w łańcuchu narzędzi na potrzeby wywołań z kodu źródłowego.
  • Kompiluje kod źródłowy Java przy użyciu jego wersji językowej.
  • Dostarcza ustawienia domyślne w przypadku elementów sourceCompatibility i targetCompatibility.

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

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

Jeśli Twój kod źródłowy jest napisany tylko w Javie, określ wersję łańcucha narzędzi Java w ten sposób:

Kotlin

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

Odlotowy

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

Jeśli źródłem jest tylko Kotlin lub mieszanka Kotlin i Javy, określ wersję łańcucha narzędzi Java w ten sposób:

Kotlin

kotlin {
    jvmToolchain(17)
}

Odlotowy

kotlin {
    jvmToolchain 17
}

Wersja łańcucha narzędzi JDK może być taka sama jak wersja JDK użyta do uruchomienia Gradle, ale pamiętaj, że pełni ona inne cele.

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.

Jeśli nie podasz żadnej wartości, domyślnie zostanie użyta łańcuch narzędzi Java lub pakiet JDK używany do uruchamiania Gradle. Zalecamy zawsze jawne określanie łańcucha narzędzi (preferowane) lub sourceCompatibility.

Określ sourceCompatibility w pliku build.gradle(.kts) modułu.

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Odlotowy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

Jakich funkcji binarnych w Javie można używać podczas kompilowania źródła Kotlin lub Javy?

Określenie targetCompatibility i jvmTarget określa wersję w formacie klasy Java używaną odpowiednio do generowania kodu bajtowego skompilowanego kodu Java i źródła Kotlin.

Przed dodaniem równoważnych funkcji Javy istniały pewne funkcje Kotlin. Pierwsi kompilatorzy języka Kotlin musieli stworzyć własne sposoby prezentowania tych funkcji. Niektóre z tych funkcji zostały później dodane do Javy. Na późniejszych poziomach jvmTarget kompilator Kotlin może bezpośrednio korzystać z funkcji Java, co może zwiększyć wydajność.

Domyślnie targetCompatibility przyjmuje tę samą wartość co sourceCompatibility, ale jeśli została określona, musi być większa lub równa sourceCompatibility.

jvmTarget domyślnie przyjmuje wersję pęku narzędzi.

Różne wersje Androida obsługują różne wersje języka Java. Możesz skorzystać z dodatkowych funkcji Javy, zwiększając liczbę targetCompatibility i jvmTarget, ale może to też zmusić Cię do zwiększenia minimalnej wersji pakietu Android SDK, aby zapewnić dostępność tej funkcji.

Kotlin

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

Odlotowy

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