Wersje Javy w kompilacji 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, musisz wybrać wersję JDK lub Javy na potrzeby kompilacji.

Omówienie zależności JDK w kompilacji Gradle
Rysunek 1. Relacje JDK w ramach kompilacji

Słowniczek

Java Development Kit (JDK)
Pakiet programistyczny Java (JDK) zawiera:
  • narzędzia, takie jak kompilator, profilator i twórca archiwum; Są one używane w tle podczas kompilacji w celu utworzenia aplikacji.
  • Biblioteki zawierające interfejsy API, które możesz wywoływać z kodu źródłowego Kotlin lub Java. Pamiętaj, że nie wszystkie funkcje są dostępne na Androidzie.
  • Maszyna wirtualna Java (JVM), czyli interpreter, który wykonuje aplikacje w Javie. JVM służy do uruchamiania środowiska IDE Android Studio i narzędzia do kompilacji Gradle. JVM nie jest używana na urządzeniach ani emulatorach z Androidem.
JetBrains Runtime (JBR)
środowisko JetBrains Runtime (JBR) to ulepszona wersja JDK, która jest dystrybuowana z Android Studio. Zawiera on kilka optymalizacji do użycia w Studio i powiązanych usługach JetBrains, ale można go też używać do uruchamiania innych aplikacji Java.

Jak wybrać JDK do uruchomienia Android Studio?

Zalecamy użycie JBR do uruchamiania Android Studio. Jest ono wdrażane i używane do testowania Android Studio. Zawiera ulepszenia, które optymalizują korzystanie z Android Studio. Aby to zrobić, nie ustawiaj zmiennej środowiskowej STUDIO_JDK.

Skrypty startowe Android Studio wyszukują JVM w takim porządku:

  1. zmienna środowiskowa STUDIO_JDK,
  2. katalog studio.jdk (w wersji Android Studio).
  3. jbr (czas wykonywania JetBrains), w rozpowszechnieniu Android Studio. Zalecane.
  4. zmienna środowiskowa JDK_HOME,
  5. zmienna środowiskowa JAVA_HOME,
  6. plik wykonywalny java w zmiennej środowiskowej PATH,

Jak wybrać JDK, który będzie uruchamiać kompilacje Gradle?

Jeśli uruchomisz Gradle za pomocą przycisków w Android Studio, Gradle będzie używać JDK określonego w ustawieniach Android Studio. Jeśli uruchomisz Gradle w terminalu, niezależnie od tego, czy korzystasz z Android Studio, czy nie, zmienna środowiskowa JAVA_HOME (jeśli jest ustawiona) określa, który JDK ma uruchamiać skrypty Gradle. Jeśli zmienna JAVA_HOME nie jest skonfigurowana, używane jest polecenie java w przypadku zmiennej środowiska PATH.

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

Podczas uruchamiania kompilacji Gradle tworzy proces zwany demonem, który wykonuje właściwą kompilację. Ten proces można powtarzać, o ile kompilacje używają tej samej wersji JDK i Gradle. Ponowne użycie demona skraca czas uruchamiania nowej maszyny JVM i inicjowania systemu kompilacji.

Jeśli rozpoczniesz kompilację z użyciem różnych wersji JDK lub Gradle, zostaną utworzone dodatkowe demony, które będą zużywać więcej pamięci i zasobów procesora.

Konfiguracja JDK w Android Studio

Aby zmodyfikować konfigurację Gradle JDK w dotychczasowym projekcie, otwórz ustawienia Gradle z poziomu Plik (lub Android Studio na komputerze Mac) > Ustawienia > Kompilacja, wykonanie, wdrożenie > Narzędzia do kompilacji > Gradle. W menu Gradle JDK dostępne są te opcje:

  • makro JAVA_HOMEGRADLE_LOCAL_JAVA_HOME,
  • Wpisy w tabeli JDK w formacie vendor-version, np. jbr-17, które są przechowywane w plikach konfiguracji Androida.
  • Pobieranie pakietu JDK
  • Dodawanie konkretnej wersji JDK
  • Wykryte lokalnie JDK-i z domyślnego katalogu instalacji JDK w systemie operacyjnym

Wybrana opcja jest przechowywana w opcji gradleJvm w pliku .idea/gradle.xml projektu, a rozwiązanie ścieżki JDK jest używane do uruchamiania Gradle, gdy jest uruchamiany przez Android Studio.

Rysunek 2. Ustawienia JDK Gradle w Android Studio.

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

  • 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 jest ustawiona na JetBrains Runtime.

Wybrana wersja JDK jest używana 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 podany compileSdk dodatkowo ograniczy dostępność symboli w Javie podczas edytowania i kompilowania kodu źródłowego.

Pamiętaj, aby wybrać wersję JDK, która jest równa lub nowsza niż wersje JDK używane przez wtyczki używane 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 korzysta z wersji JDK, która jest starsza niż ta, która jest wymagana, 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 Java mogę używać w kodzie źródłowym w języku Java lub Kotlin?

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

Kotlin

android {
    ...
    compileSdk = 33
}

Groovy

android {
    ...
    compileSdk 33
}

Każda wersja Androida obsługuje określoną wersję JDK i podzbiór dostępnych interfejsów API Java. Jeśli używasz interfejsu Java API dostępnego w compileSdk, który nie jest dostępny w określonej minSdk, możesz spróbować użyć tego interfejsu API w starszej wersji Androida za pomocą procesu zwanego desugaringiem. Informacje o obsługiwanych interfejsach API znajdziesz w artykule Interfejsy API Java 11 i nowsze dostępne dzięki desugaringowi.

Z tej tabeli dowiesz się, która wersja Javy jest obsługiwana przez każdy interfejs API Androida oraz gdzie znaleźć informacje o tym, które interfejsy API Javy są dostępne.

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

Która wersja JDK kompiluje mój kod źródłowy w Javie?

Zbiór narzędzi Java JDK zawiera kompilator Java, który służy do kompilowania dowolnego kodu źródłowego Java. Ta wersja JDK uruchamia też javadoc i testy jednostkowe podczas kompilacji.

Domyślnie toolchain to JDK używany do uruchamiania Gradle. Jeśli używasz domyślnej wersji i uruchamiasz kompilację na różnych maszynach (np. na komputerze lokalnym i na osobnym serwerze ciągłej integracji), wyniki kompilacji mogą się różnić, jeśli używasz różnych wersji JDK.

Aby utworzyć bardziej spójną kompilację, możesz wyraźnie określić wersję łańcucha narzędzi Java. Określając to:

  • Znajduje zgodną wersję JDK na systemie, na którym działa kompilacja.
    • Jeśli nie ma zgodnego pakietu JDK (a jest zdefiniowany rozwiązywacz łańcucha narzędzi), pobiera go.
  • Udostępnia interfejsy API Javy narzędzia do kompilacji do wywołań z kodu źródłowego.
  • Kompiluje kod źródłowy w języku Java, korzystając z odpowiedniej wersji językowej.
  • Domyślne wartości dostaw dla sourceCompatibility i targetCompatibility.

Zalecamy, aby zawsze określać łańcuch narzędzi Java i upewnić się, że zainstalowano określony pakiet JDK, lub dodać do kompilacji rozwiązanie ł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 narzędzie w górnym poziomie pliku build.gradle(.kts) modułu.

Podaj wersję łańcucha narzędzi Java w ten sposób:

Kotlin

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

Groovy

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

Ta metoda działa, jeśli źródło to Kotlin, Java lub obie te technologie.

Wersja toolchain JDK 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 języka Java mogę używać w kodzie źródłowym w języku 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 kod Kotlin.

W pliku build.gradle(.kts) w module określ wartość sourceCompatibility w ten sposób:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

Jeśli nie podasz żadnej wartości, ta właściwość zostanie domyślnie ustawiona na wersję kompilatora Java. Jeśli nie używasz zestawu narzędzi Java, domyślnie wybrana zostanie wersja wybrana przez wtyczkę Gradle dla Androida (np. Java 8 lub nowsza).

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

Właściwości targetCompatibilityjvmTarget określają wersję formatu klasy Java używaną podczas generowania kodu bajtowego odpowiednio dla skompilowanego kodu źródłowego w języku Java i Kotlin.

Niektóre funkcje Kotlina istniały przed dodaniem odpowiednich funkcji Java. 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 jvmTarget kompilator Kotlina może bezpośrednio korzystać z funkcji Java, co może skutkować większą wydajnością.

Różne wersje Androida obsługują różne wersje Javy. Aby korzystać z dodatkowych funkcji Java, możesz zwiększyć wartości targetCompatibilityjvmTarget, ale może to wymagać również zwiększenia minimalnej wersji pakietu Android SDK, aby mieć pewność, że funkcja będzie dostępna.

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

Kotlin

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

Groovy

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

Jeśli nie podasz żadnej wartości, te właściwości zostaną domyślnie ustawione na wersję łańcucha narzędzi Java. Jeśli nie używasz łańcucha narzędzi Java, wartości domyślne mogą się różnić i spowodować problemy z kompilacją. Dlatego zalecamy zawsze jawne określenie tych wartości lub użycie zestawu narzędzi Java.