Versiones de Java en compilaciones de Android

Ya sea que tu código fuente esté escrito en Java, Kotlin o ambos, hay varios lugares en los que debes elegir una versión de lenguaje JDK o Java para tu compilación.

Descripción general de las relaciones de JDK en una compilación de Gradle

Glosario

Java Development Kit (JDK)
El Java Development Kit (JDK) contiene lo siguiente:
  • Herramientas, como el compilador, el generador de perfiles y el creador de archivos. Estos se usan en segundo plano durante la compilación para crear la aplicación.
  • Bibliotecas que contienen APIs a las que puedes llamar desde el código fuente de Kotlin o Java. Ten en cuenta que no todas las funciones están disponibles en Android.
  • Máquina virtual Java (JVM), un intérprete que ejecuta aplicaciones de Java. Usarás la JVM para ejecutar el IDE de Android Studio y la herramienta de compilación Gradle. La JVM no se usa en emuladores ni dispositivos Android.
Entorno de ejecución de JetBrains (JBR)
JetBrains Runtime (JBR) es un JDK mejorado que se distribuye con Android Studio. Incluye varias optimizaciones para usar en Studio y los productos relacionados de JetBrains, pero también se puede usar para ejecutar otras aplicaciones de Java.

¿Cómo elijo un JDK para ejecutar Android Studio?

Te recomendamos que uses JBR para ejecutar Android Studio. Se implementa y se usa para probar Android Studio e incluye mejoras para un uso óptimo de Android Studio. Para asegurarte de esto, no configures la variable de entorno STUDIO_JDK.

Las secuencias de comandos de inicio para Android Studio buscan una JVM en el siguiente orden:

  1. Con la variable de entorno STUDIO_JDK
  2. Directorio studio.jdk (en la distribución de Android Studio)
  3. Directorio jbr (entorno de ejecución de JetBrains), en la distribución de Android Studio Recomendado
  4. Con la variable de entorno JDK_HOME
  5. Con la variable de entorno JAVA_HOME
  6. Archivo ejecutable java en la variable de entorno PATH

¿Cómo elijo el JDK que ejecuta mis compilaciones de Gradle?

Si ejecutas Gradle con los botones de Android Studio, el JDK establecido en la configuración de Android Studio se usa para ejecutar Gradle. Si ejecutas Gradle en una terminal, ya sea dentro o fuera de Android Studio, la variable de entorno JAVA_HOME (si está configurada) determina qué JDK ejecuta las secuencias de comandos de Gradle. Si JAVA_HOME no está configurado, usa el comando java en la variable de entorno PATH.

Para obtener resultados más coherentes, asegúrate de establecer la variable de entorno JAVA_HOME y la configuración de JDK de Gradle en Android Studio en ese mismo JDK.

Cuando ejecutas tu compilación, Gradle crea un proceso llamado daemon para realizar la compilación real. Este proceso se puede volver a usar, siempre que las compilaciones usen la misma versión de JDK y Gradle. La reutilización de un daemon reduce el tiempo necesario para iniciar una nueva JVM e inicializar el sistema de compilación.

Si inicias compilaciones con diferentes versiones de JDK o Gradle, se crean daemons adicionales, que consumen más CPU y memoria.

Configuración de Gradle JDK en Android Studio

Para modificar la configuración de Gradle JDK del proyecto existente, abre la configuración de Gradle desde File (o Android Studio en macOS) > Settings > Build, Execution, Deployment > Build Tools > Gradle. El menú desplegable Gradle JDK contiene las siguientes opciones para seleccionar:

  • Macros como JAVA_HOME y GRADLE_LOCAL_JAVA_HOME
  • Entradas de tabla de JDK en formato vendor-version, como jbr-17, que se almacenan en los archivos de configuración de Android
  • Cómo descargar un JDK
  • Cómo agregar un JDK específico
  • Se detectaron JDK de forma local desde el directorio de instalación predeterminado de JDK del sistema operativo.

La opción seleccionada se almacena en la opción gradleJvm en el archivo .idea/gradle.xml del proyecto, y la resolución de ruta de acceso de JDK se usa para ejecutar Gradle cuando se inicia mediante Android Studio.

Figura 1: Configuración de Gradle JDK en Android Studio.

Las macros habilitan la selección dinámica de la ruta de acceso del JDK del proyecto:

  • JAVA_HOME: Usa la variable de entorno con el mismo nombre.
  • GRADLE_LOCAL_JAVA_HOME: Usa la propiedad java.home en el archivo .gradle/config.properties, que es el entorno de ejecución de JetBrains predeterminado.

El JDK seleccionado se usa para ejecutar tu compilación de Gradle y resolver referencias de la API de JDK cuando se editan las secuencias de comandos de compilación y el código fuente. Ten en cuenta que el compileSdk especificado restringirá aún más los símbolos Java que estarán disponibles cuando edites y compiles tu código fuente.

Asegúrate de elegir una versión de JDK que sea superior o igual a las versiones de JDK que usan los complementos que usas en tu compilación de Gradle. Para determinar la versión mínima de JDK requerida para el complemento de Android para Gradle (AGP), consulta la tabla de compatibilidad en las notas de la versión.

Por ejemplo, la versión 8.x del complemento de Android para Gradle requiere JDK 17. Si intentas ejecutar una compilación de Gradle que la usa con una versión anterior del JDK, se mostrará un mensaje como el siguiente:

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`.

¿Qué APIs de Java puedo usar en mi código fuente Java o Kotlin?

Una aplicación para Android puede usar algunas de las APIs definidas en un JDK, pero no todas. El SDK de Android define las implementaciones de muchas funciones de la biblioteca de Java como parte de sus APIs disponibles. La propiedad compileSdk especifica qué versión del SDK de Android se debe usar cuando se compila el código fuente de Kotlin o Java.

Kotlin

android {
    ...
    compileSdk = 33
}

Groovy

android {
    ...
    compileSdk 33
}

Cada versión de Android admite una versión específica del JDK y un subconjunto de las APIs de Java disponibles. Si usas una API de Java que está disponible en un compileSdk que no está disponible en el minSdk especificado, es posible que puedas usar la API en la versión anterior de Android mediante un proceso conocido como expansión de sintaxis. Consulta las APIs de Java 11 y versiones posteriores disponibles con la expansión de sintaxis para conocer las APIs compatibles.

Usa esta tabla para determinar qué versión de Java es compatible con cada API de Android y dónde encontrar detalles sobre qué APIs de Java están disponibles.

Android Java Funciones de lenguaje y API compatibles
14 (nivel de API 34) 17 Bibliotecas principales
13 (nivel de API 33) 11 Bibliotecas principales
12 (nivel de API 32) 11 API de Java
11 y anteriores Versiones de Android

¿Qué JDK compila mi código fuente Java?

El JDK de la cadena de herramientas de Java contiene el compilador de Java utilizado para compilar cualquier código fuente de Java. Este JDK también ejecuta pruebas de unidades y javadoc durante la compilación.

De forma predeterminada, la cadena de herramientas es el JDK que se usó para ejecutar Gradle. Si usas el valor predeterminado y ejecutas una compilación en diferentes máquinas (por ejemplo, tu máquina local y un servidor de integración continua independiente), los resultados de la compilación pueden diferir si se usan diferentes versiones de JDK.

Para crear una compilación más coherente, puedes especificar explícitamente una versión de la cadena de herramientas de Java. Especificando lo siguiente:

  • Ubica un JDK compatible en el sistema que ejecuta la compilación.
    • Si no existe un JDK compatible (y se define un agente de resolución de la cadena de herramientas), se descarga uno.
  • Expone las APIs de Java de la cadena de herramientas para llamadas desde código fuente.
  • Compila fuentes de Java con su versión en lenguaje Java.
  • Proporciona valores predeterminados para sourceCompatibility y targetCompatibility.

Te recomendamos que siempre especifiques la cadena de herramientas de Java y que te asegures de que el JDK especificado esté instalado o que agregues un agente de resolución de la cadena de herramientas a tu compilación.

Puedes especificar la cadena de herramientas si tu código fuente está escrito en Java, Kotlin o ambos. Especifica la cadena de herramientas en el nivel superior del archivo build.gradle(.kts) de tu módulo.

Si tu código fuente solo está escrito en Java, especifica la versión de la cadena de herramientas de Java de la siguiente manera:

Kotlin

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

Groovy

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

Si tu fuente es solo Kotlin o una combinación de Kotlin y Java, especifica la versión de la cadena de herramientas de Java de la siguiente manera:

Kotlin

kotlin {
    jvmToolchain(17)
}

Groovy

kotlin {
    jvmToolchain 17
}

La versión del JDK de la cadena de herramientas puede ser la misma que el que se usa para ejecutar Gradle, pero ten en cuenta que tienen diferentes propósitos.

¿Qué funciones de origen del lenguaje Java puedo usar en mi código fuente Java?

La propiedad sourceCompatibility determina qué funciones del lenguaje Java están disponibles durante la compilación de la fuente de Java. Esto no afecta el código fuente de Kotlin.

Si no se especifica, el valor predeterminado es la cadena de herramientas de Java o el JDK que se usan para ejecutar Gradle. Te recomendamos que siempre especifiques de forma explícita una cadena de herramientas (preferido) o sourceCompatibility.

Especifica sourceCompatibility en el archivo build.gradle(.kts) de tu módulo.

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

¿Qué funciones binarias de Java se pueden usar cuando compilo mi código fuente de Kotlin o Java?

La especificación de targetCompatibility y jvmTarget determina la versión del formato de clase Java que se usa cuando se genera el código de bytes para la fuente compilada de Java y Kotlin, respectivamente.

Algunas funciones de Kotlin existían antes de que se agregaran las funciones equivalentes de Java. Los primeros compiladores de Kotlin tuvieron que crear su propia forma de representar esas funciones de Kotlin. Posteriormente, algunas de estas funciones se agregaron a Java. Con niveles posteriores de jvmTarget, el compilador de Kotlin podría usar directamente la función de Java, lo que podría mejorar el rendimiento.

targetCompatibility tiene el mismo valor predeterminado que sourceCompatibility, pero si se especifica, debe ser mayor o igual que sourceCompatibility.

jvmTarget usa la versión de la cadena de herramientas de forma predeterminada.

Las diferentes versiones de Android admiten diferentes versiones de Java. Puedes aprovechar las funciones adicionales de Java si aumentas targetCompatibility y jvmTarget, pero esto podría obligarte a aumentar también la versión mínima del SDK de Android para asegurarte de que la función esté disponible.

Kotlin

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

Groovy

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