Wersje Javy w kompilacji Androida

Niezależnie od tego, czy kod źródłowy jest napisany w Javie, Kotlinie czy w obu tych językach, musisz wybrać wersję JDK lub Javy w kilku miejscach.

Omówienie relacji JDK w kompilacji Gradle
Rysunek 1. Relacje JDK w kompilacji

Słowniczek

Java Development Kit (JDK)
Zestaw Java Development Kit (JDK) zawiera:
  • Narzędzia, takie jak kompilator, profiler i narzędzie do tworzenia archiwów. Są one używane w tle podczas kompilacji do tworzenia aplikacji.
  • Biblioteki zawierające interfejsy API, które można wywoływać z kodu źródłowego w Kotlinie lub Javie. Pamiętaj, że nie wszystkie funkcje są dostępne na Androidzie.
  • Java Virtual Machine (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 w emulatorach.
JetBrains Runtime (JBR)
JetBrains Runtime (JBR) to ulepszony pakiet JDK dystrybuowany z Androidem Studio. Zawiera kilka optymalizacji do użytku w Studio i powiązanych produktach JetBrains, ale można go też używać do uruchamiania innych aplikacji w Javie.

Jak wybrać JDK do uruchamiania Androida Studio?

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

Skrypty uruchamiania Androida Studio szukają JVM w tej kolejności:

  1. zmienna środowiskowa STUDIO_JDK
  2. katalog studio.jdk (w dystrybucji Androida Studio)
  3. katalog jbr (JetBrains Runtime) w dystrybucji Androida Studio. Zalecane.
  4. zmienna środowiskowa JDK_HOME
  5. zmienna środowiskowa JAVA_HOME
  6. plik wykonywalny java w zmiennej środowiskowej PATH

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

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

Aby uzyskać najbardziej spójne wyniki, upewnij się, że ustawiono zmienną środowiskową JAVA_HOME i konfigurację JDK Gradle w Android Studio na to samo JDK.

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

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

Konfiguracja JDK Gradle w Android Studio

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

  • 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 konfiguracyjnych Androida
  • Pobieranie JDK
  • Dodawanie konkretnego JDK
  • Lokalnie wykryte JDK z domyślnego katalogu instalacyjnego JDK systemu operacyjnego

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

Rysunek 2. Ustawienia JDK Gradle w Android Studio.

Makra umożliwiają dynamiczne wybieranie ś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 jest ustawiona na JetBrains Runtime.

Wybrane JDK jest używane 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 określony compileSdk dodatkowo ograniczy, które symbole Java będą dostępne podczas edytowania i kompilowania kodu źródłowego.

Wybierz wersję JDK, która jest nowsza lub równa wersjom JDK używanym 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 JDK 17. Jeśli spróbujesz uruchomić kompilację Gradle, która używa wcześniejszej wersji JDK, wyświetli 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`.

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

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 jako część dostępnych interfejsów API. Właściwość compileSdk określa, której wersji Android SDK należy użyć podczas kompilowania kodu źródłowego w Kotlinie lub Javie.

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 Java API. Jeśli używasz interfejsu Java API, który jest dostępny w a compileSdk który nie jest dostępny w określonym minSdk, możesz użyć interfejsu API w starszej wersji Androida za pomocą procesu zwanego desugaringiem. Obsługiwane interfejsy API znajdziesz w artykule Interfejsy Java 11+ API dostępne dzięki desugaringowi.

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

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

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

JDK łańcucha narzędzi Java zawiera kompilator Java używany do kompilowania dowolnego kodu źródłowego w Javie. To JDK uruchamia też javadoc i testy jednostkowe podczas kompilacji.

Łańcuch narzędzi domyślnie używa JDK używanego do uruchamiania Gradle. Jeśli używasz domyślnego JDK 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żywane są różne wersje JDK.

Aby uzyskać bardziej spójną kompilację, możesz wyraźnie określić wersję łańcucha narzędzi Java. Określenie tej wersji:

  • Znajduje zgodne JDK w systemie, w którym jest uruchamiana kompilacja.
    • Jeśli nie ma zgodnego JDK (i jest zdefiniowany resolver łańcucha narzędzi), pobiera je.
  • Udostępnia interfejsy Java API łańcucha narzędzi do wywoływania z kodu źródłowego.
  • Kompiluje źródło Java za pomocą jego 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ślone JDK jest zainstalowane, lub dodać do kompilacji resolver łańcucha narzędzi.

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

Wersję łańcucha narzędzi Java określ 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ło jest w Kotlinie, Javie lub w obu tych językach.

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

Jakich funkcji języka Java mogę używać w kodzie źródłowym w Javie?

Właściwość sourceCompatibility określa, które funkcje języka Java są dostępne podczas kompilacji źródła Java. Nie ma 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, ta właściwość domyślnie przyjmie wersję łańcucha narzędzi Java. Jeśli nie używasz łańcucha narzędzi Java, domyślnie zostanie użyta wersja wybrana przez wtyczkę Androida do obsługi Gradle (np. Java 8 lub nowsza).

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

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

Niektóre funkcje Kotlin istniały, zanim dodano równoważne funkcje Java. Wczesne kompilatory Kotlin musiały tworzyć własne sposoby reprezentowania tych funkcji Kotlin. Niektóre z tych funkcji zostały później dodane do Javy. W przypadku nowszych poziomów targetCompatibility kompilator Kotlin może bezpośrednio używać funkcji Java, co może skutkować lepszą wydajnością.

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

Pamiętaj, że targetCompatibility musi być większa lub równa sourceCompatibility. W praktyce sourceCompatibility i targetCompatibility powinny zwykle używać tej samej wartości. 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 Kotlin starszej niż 2.2, musisz też ustawić kotlinOptions:

Kotlin

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

Dynamiczny

android {
    kotlinOptions {
        jvmTarget = "17"
    }
}

Jeśli nie podasz żadnej wartości, te właściwości domyślnie przyjmują 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 powodować problemy z kompilacją. Dlatego zalecamy, aby zawsze wyraźnie określać te wartości lub używać łańcucha narzędzi Java.