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, w kilku miejscach musisz wybrać wersję JDK lub języka Java na potrzeby kompilacji.

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

Słowniczek

Java Development Kit (JDK)
Pakiet Java Development Kit (JDK) zawiera:
  • Narzędzia, takie jak kompilator, profiler i program 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 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 w Javie. JVM służy do uruchamiania środowiska programistycznego Android Studio i narzędzia do kompilacji Gradle. Na urządzeniach z Androidem ani na emulatorach nie używa się JVM.
JetBrains Runtime (JBR)
JetBrains Runtime (JBR) to ulepszona wersja JDK dystrybuowana z Android 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ć pakiet JDK do uruchomienia Androida Studio?

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

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

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

Jak wybrać, która wersja JDK ma uruchamiać kompilacje Gradle?

Jeśli uruchamiasz Gradle za pomocą przycisków w Android Studio, do uruchomienia Gradle używane jest środowisko JDK ustawione w ustawieniach Android Studio. Jeśli uruchomisz Gradle w terminalu, wewnątrz lub na zewnątrz Android Studio, zmienna środowiskowa JAVA_HOME (jeśli jest ustawiona) określi, która wersja JDK uruchomi skrypty Gradle. Jeśli JAVA_HOME nie jest ustawiona, używa polecenia java w zmiennej środowiskowej PATH.

Aby uzyskać najbardziej spójne wyniki, ustaw JAVA_HOMEzmienną środowiskową i konfigurację Gradle JDK w Android Studio na to samo środowisko JDK.

Podczas uruchamiania kompilacji Gradle tworzy proces zwany demonem, który przeprowadza kompilację. Ten proces można ponownie wykorzystać, o ile kompilacje korzystają z tej samej wersji JDK i Gradle. Ponowne użycie demona skraca czas uruchamiania nowej maszyny 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 Gradle JDK w Android Studio

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

  • Makra takie jak JAVA_HOMEGRADLE_LOCAL_JAVA_HOME
  • Wpisy w tabeli JDK w formacie vendor-version, np. jbr-17, które są przechowywane w plikach konfiguracyjnych Androida.
  • Pobieranie pakietu JDK
  • Dodawanie konkretnego pakietu JDK
  • lokalnie wykryte zestawy JDK z domyślnego katalogu instalacji zestawu JDK w systemie operacyjnym;

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 rozpoczęciu pracy w Android Studio.

Rysunek 2. Ustawienia Gradle JDK 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.

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 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 nowsza lub równa wersjom JDK używanym przez wtyczki 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 tej wersji z wcześniejszą 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/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 w Javie lub Kotlinie?

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 jako część dostępnych interfejsów API. Właściwość compileSdk określa, której wersji pakietu SDK Androida 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ślonym minSdk, możesz używać interfejsu API we wcześniejszej wersji Androida w procesie zwanym desugaringiem. Listę obsługiwanych interfejsów API znajdziesz w artykule Interfejsy API Java 11+ dostępne dzięki desugaryzacji.

Z tej tabeli dowiesz się, która wersja Javy jest obsługiwana przez poszczególne interfejsy API Androida, oraz 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 lat i młodsze Wersje Androida

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

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

Domyślnie łańcuch narzędzi używa pakietu JDK, który jest używany do uruchamiania Gradle. Jeśli używasz domyślnej wersji i uruchamiasz kompilację na różnych komputerach (np. na komputerze lokalnym i osobnym serwerze 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 jawnie określić wersję łańcucha narzędzi Java. Określenie tego:

  • Wyszukuje zgodny pakiet JDK w systemie, w którym jest przeprowadzana kompilacja.
    • Jeśli nie ma zgodnego pakietu JDK (a zdefiniowany jest moduł rozpoznawania łańcucha narzędzi), pobiera go.
  • Udostępnia interfejsy API Java łańcucha narzędzi do wywołań z kodu źródłowego.
  • Kompiluje źródło w Javie przy użyciu wersji języka Java.
  • Określa domyślne wartości parametrów sourceCompatibilitytargetCompatibility.

Zalecamy, aby zawsze określać łańcuch narzędzi Java i upewniać się, że określony pakiet JDK jest zainstalowany, lub dodawać do kompilacji rozwiązanie do rozwiązywania łańcucha narzędzi.

Możesz określić łańcuch 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ę łańcucha narzędzi Java w ten sposób:

Kotlin

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

Groovy

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

Ta funkcja działa, jeśli źródłem jest Kotlin, Java lub połączenie tych języków.

Wersja JDK łańcucha 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.

Jakich funkcji 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 w tym języku. Nie ma to wpływu na źródło Kotlin.

W pliku build.gradle(.kts) modułu określ 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, domyślnie zostanie użyta wersja zestawu narzędzi Java. Jeśli nie używasz łańcucha narzędzi Java, domyślnie wybierana jest wersja wybrana przez wtyczkę Androida do Gradle (np. Java 8 lub nowsza).

Jakich funkcji binarnych Javy mogę 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 dla skompilowanych źródeł Java i Kotlin.

Niektóre funkcje języka Kotlin istniały, zanim dodano ich odpowiedniki w języku Java. Wczesne kompilatory języka Kotlin musiały tworzyć własne sposoby reprezentowania tych funkcji. Niektóre z tych funkcji zostały później dodane do języka Java. W późniejszych wersjach jvmTarget kompilator Kotlina może bezpośrednio korzystać z funkcji Javy, co może skutkować lepszą wydajnością.

Różne wersje Androida obsługują różne wersje Javy. Możesz skorzystać z dodatkowych funkcji Javy, zwiększając wartości targetCompatibilityjvmTarget, ale może to wymagać zwiększenia minimalnej wersji pakietu Android SDK, aby mieć pewność, że funkcja jest dostępna.

Pamiętaj, że targetCompatibility musi być większe lub równe sourceCompatibility. W praktyce wartości sourceCompatibility, targetCompatibility i jvmTarget powinny być takie same. 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 określisz tych właściwości, domyślnie zostanie użyta wersja zestawu 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ą. Z tego powodu zalecamy, aby zawsze wyraźnie określać te wartości lub używać zestawu narzędzi Java.