Wersje Javy w kompilacjach 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ć 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 Java Development Kit (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żna 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 z Androidem ani na emulatorach.
Środowisko wykonawcze JetBrains (JBR)
środowisko JetBrains Runtime (JBR) to ulepszona wersja JDK, która jest dystrybuowana z Android Studio. Zawiera ona kilka optymalizacji do stosowania w Studio i powiązanych usługach JetBrains, ale można jej też używać do uruchamiania innych aplikacji w języku Java.

Jak wybrać pakiet JDK do uruchomienia Android Studio?

Do uruchamiania Android Studio zalecamy używanie JBR. Jest wdrażany wraz z Androidem Studio i używany do jego testowania. Zawiera też ulepszenia pozwalające na optymalne wykorzystanie tego środowiska. Aby to zrobić, nie ustawiaj zmiennej środowiskowej STUDIO_JDK.

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

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

Jak wybrać pakiet JDK uruchamiający moje 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 środowiskowej 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 nazywany demonem, który wykonuje rzeczywistą kompilację. Tego procesu można użyć ponownie, o ile kompilacje korzystają z tej samej wersji pakietu JDK i Gradle. Ponowne użycie demona skraca czas uruchamiania nowej JVM i inicjowania systemu kompilacji.

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

Konfiguracja JDK w Android Studio

Aby zmodyfikować konfigurację Gradle JDK w istniejącym projekcie, otwórz ustawienia Gradle z poziomu Plik (lub Android Studio na komputerze Mac) > Ustawienia > Kompilacja, wykonanie, wdrożenie > Narzędzia do kompilacji > Gradle. Menu Gradle JDK zawiera następujące opcje do wyboru:

  • Makra, np. 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 pakietu JDK
  • Dodawanie określonego pakietu 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 rozdzielczość ścieżki JDK jest używana do uruchamiania Gradle w przypadku uruchamiania w Android Studio.

Rysunek 2. Ustawienia Gradle JDK 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 środowisko wykonawcze JetBrains.

Wybrana wersja JDK jest używana do uruchamiania kompilacji Gradle i rozwiązywania odwołań do interfejsu JDK podczas edytowania skryptów kompilacji i kodu źródłowego. Pamiętaj, że wybrana opcja compileSdk dodatkowo ograniczy dostępność symboli Java podczas edytowania i generowania 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 Android do obsługi Gradle (AGP), zajrzyj do tabeli 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 z wcześniejszą wersją pakietu JDK, otrzymasz 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. Pakiet 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 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 API Java, który jest dostępny w compileSdk, który nie jest dostępny w podanym minSdk, może być możliwe użycie interfejsu API we wcześniejszej wersji Androida za pomocą procesu zwanego usunięciem. Listę obsługiwanych interfejsów API znajdziesz w artykule o interfejsach API w języku Java 11+ dostępnych w ramach desugaringu.

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 (interfejs API 32) 11 Interfejs Java API
11 i mniej Wersje Androida

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

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

Domyślnie używana jest platforma JDK używana 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 jawnie określić wersję łańcucha narzędzi Java. Określenie:

  • Lokalizuje zgodny pakiet JDK w systemie, w którym uruchamiana jest kompilacja.
    • Jeśli nie istnieje zgodny pakiet JDK (i został zdefiniowany resolver łańcucha narzędzi), pobiera go.
  • Udostępnia interfejsy API w Javie dla łańcucha narzędzi dla wywołań kodu źródłowego.
  • Kompiluje źródło w Javie z użyciem jej wersji językowej.
  • Domyślne ustawienia zasobów reklamowych w przypadku 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 łańcuch narzędzi na najwyższym 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)
    }
}

Odlotowe

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

Sprawdza się to, jeśli źródłem jest Kotlin lub Java albo ich kombinacja.

Wersja łańcucha narzędzi JDK może być taka sama jak pakiet JDK używany 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 moim kodzie źródłowym Java?

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

Określ sourceCompatibility w pliku build.gradle(.kts) modułu w następujący sposób:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

Jeśli jej nie określisz, domyślnie ustawimy łańcuch narzędzi Java. Jeśli nie używasz zestawu narzędzi Java, domyślnie wybrana zostanie wersja wybrana przez wtyczkę Android Gradle (np. Java 8 lub nowsza).

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

Właściwości targetCompatibility i jvmTarget określają wersję formatu klasy Java używaną odpowiednio do generowania kodu bajtowego odpowiednio dla skompilowanego źródła Java i Kotlina.

Niektóre funkcje Kotlina istniały przed dodaniem odpowiednich funkcji Java. Wczesne kompilatory Kotlin musiały opracować własny sposób przedstawienia tych cech Kotlin. 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 języka Java. 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 SDK Androida, aby mieć pewność, że funkcja będzie dostępna.

Pamiętaj, że targetCompatibility musi być równa sourceCompatibility lub większa. 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"
    }
}

Odlotowe

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ć, co może powodować problemy z kompilacją. Dlatego zalecamy, aby zawsze wyraźnie określać te wartości lub użyć łańcucha narzędzi języka Java.