Complemento de Android para Gradle 4.0.0 (abril de 2020)

Esta versión del complemento para Android requiere lo siguiente:

4.0.1 (julio de 2020)

Esta actualización menor es compatible con los nuevos parámetros de configuración predeterminados y las funciones para la visibilidad de los paquetes en Android 11.

En las versiones anteriores de Android, era posible ver una lista de todas las apps instaladas en un dispositivo. A partir de Android 11 (nivel de API 30), de forma predeterminada, las apps solo tienen acceso a una lista filtrada de paquetes instalados. Para ver una lista más amplia de las apps en el sistema, ahora debes agregar un elemento <queries> en el manifiesto de Android de la app o biblioteca.

El complemento de Android para Gradle 4.1 y versiones posteriores ya es compatible con la nueva declaración <queries>. Sin embargo, las versiones anteriores no lo son. Si agregas el elemento <queries> o si comienzas a depender de una biblioteca o un SDK que admite la orientación a Android 11, es posible que se produzcan errores de combinación de manifiestos durante la compilación de tu app.

Para solucionar este problema, lanzaremos un conjunto de parches para el AGP 3.3 y versiones posteriores. Si usas una versión anterior del AGP, actualízalo a una de las siguientes versiones:

Versión mínima Versión predeterminada Notas
Gradle 6.1.1 6.1.1 Para obtener más información, consulta cómo actualizar Gradle.
Herramientas de desarrollo del SDK 29.0.2 29.0.2 Instala o configura las herramientas de compilación del SDK.

Para obtener más información sobre esta nueva función, consulta Visibilidad de los paquetes en Android 11.

Funciones nuevas

Esta versión del complemento de Android para Gradle incluye las siguientes funciones nuevas:

Compatibilidad con Build Analyzer de Android Studio

La ventana Build Analyzer te ayuda a comprender y diagnosticar problemas con el proceso de compilación, como optimizaciones inhabilitadas y tareas mal configuradas. Esta función está disponible cuando usas Android Studio 4.0 y versiones posteriores con el complemento de Android para Gradle 4.0.0 y versiones posteriores. Puedes abrir la ventana Build Analyzer de Android Studio de la siguiente manera:

  1. Si aún no lo hiciste, selecciona la opción Build > Make Project de la barra de menú para compilar tu app.
  2. En la barra de menú, selecciona View > Tool Windows > Build.
  3. En la ventana Build, abre la ventana Build Analyzer de una de las siguientes maneras:
    • Cuando Android Studio termine de compilar el proyecto, haz clic en la pestaña Build Analyzer.
    • Cuando Android Studio termine de compilar el proyecto, haz clic en el vínculo que se encuentra en el lado derecho de la ventana Build Output.

En el lado izquierdo, la ventana Build Analyzer organiza los posibles problemas de compilación en un árbol. Puedes explorar cada problema y hacer clic en ellos para analizar los detalles en el panel de la derecha. Cuando Android Studio analiza tu compilación, procesa el conjunto de tareas que determinaron la duración de la compilación y proporciona una visualización para ayudarte a comprender el impacto de cada una de esas tareas. Para obtener más detalles sobre las advertencias, expande el nodo Warnings.

Si quieres obtener más información, consulta cómo identificar regresiones de velocidad de compilación.

Expansión de sintaxis de la biblioteca de Java 8 en D8 y R8

El complemento de Android para Gradle ahora admite la utilización de varias APIs de lenguaje Java 8 sin necesidad de un nivel de API mínimo para tu app.

Mediante un proceso llamado expansión de sintaxis, el compilador DEX, D8, de Android Studio 3.0 y versiones posteriores ya proporcionaba compatibilidad sustancial con funciones del lenguaje Java 8 (como expresiones lambda, métodos de interfaz predeterminados, la prueba con recursos, etc.). En Android Studio 4.0, se amplió el motor correspondiente para poder expandir la sintaxis de las APIs del lenguaje Java. Eso significa que ahora puedes incluir APIs de lenguaje estándar que solo estaban disponibles en las versiones recientes de Android (como java.util.streams) en apps que admiten versiones anteriores de Android.

El siguiente conjunto de APIs es compatible con esta versión:

  • Flujos secuenciales (java.util.stream)
  • Un subconjunto de java.time
  • java.util.function
  • Adiciones recientes a java.util.{Map,Collection,Comparator}
  • Opcionales (java.util.Optional, java.util.OptionalInt y java.util.OptionalDouble) y algunas otras clases nuevas que son útiles para las APIs anteriores
  • Algunas adiciones a java.util.concurrent.atomic (métodos nuevos en AtomicInteger, AtomicLong y AtomicReference)
  • ConcurrentHashMap (con correcciones de errores para Android 5.0)

Para admitir esas APIs de lenguaje, D8 compila un archivo DEX de biblioteca independiente que contiene una implementación de las APIs faltantes y lo incluye en tu app. El proceso de expansión de sintaxis reescribe el código de tu app para que se pueda usar esa biblioteca durante el tiempo de ejecución.

Para agregar compatibilidad con esas APIs de lenguaje, incluye lo siguiente en el archivo build.gradle del módulo de la app:

android {
  defaultConfig {
    // Required when setting minSdkVersion to 20 or lower
    multiDexEnabled true
  }

compileOptions { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true // Sets Java compatibility to Java 8 sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }

dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.4' }

android {
  defaultConfig {
    // Required when setting minSdkVersion to 20 or lower
    multiDexEnabled = true
  }

compileOptions { // Flag to enable support for the new language APIs isCoreLibraryDesugaringEnabled = true // Sets Java compatibility to Java 8 sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } }

dependencies { coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.0.4") }

Ten en cuenta que también es posible que debas incluir el fragmento de código anterior en un archivo build.gradle del módulo de biblioteca en los siguientes casos:

  • Las pruebas de instrumentación del módulo de biblioteca usan estas APIs de lenguaje (ya sea directamente o a través del módulo de biblioteca o sus dependencias). Por lo tanto, las APIs faltantes se proporcionan para el APK de la prueba de instrumentación.

  • Deseas ejecutar lint en el módulo de biblioteca de forma aislada. Esto permite que lint reconozca los usos válidos de las APIs de lenguaje y evite informar advertencias falsas.

Opciones nuevas para habilitar o inhabilitar las funciones de compilación

El complemento de Android para Gradle 4.0.0 presenta una nueva manera de controlar las funciones de compilación que deseas habilitar o inhabilitar, como la Vinculación de vista y la Vinculación de datos. De forma predeterminada, se inhabilitarán las funciones nuevas que se agreguen. Luego, podrás usar el bloque buildFeatures para habilitar solamente las funciones que desees, lo que ayudará a optimizar el rendimiento de la compilación del proyecto. Puedes configurar las opciones de cada módulo en el archivo build.gradle de nivel de módulo de la siguiente manera:

android {
  // The default value for each feature is shown below. You can change the value to
  // override the default behavior.
  buildFeatures {
    // Determines whether to generate a BuildConfig class.
    buildConfig = true
    // Determines whether to support View Binding.
    // Note that the viewBinding.enabled property is now deprecated.
    viewBinding = false
    // Determines whether to support Data Binding.
    // Note that the dataBinding.enabled property is now deprecated.
    dataBinding = false
    // Determines whether to generate binder classes for your AIDL files.
    aidl = true
    // Determines whether to support RenderScript.
    renderScript = true
    // Determines whether to support injecting custom variables into the module’s R class.
    resValues = true
    // Determines whether to support shader AOT compilation.
    shaders = true
  }
}
android {
  // The default value for each feature is shown below. You can change the value to
  // override the default behavior.
  buildFeatures {
    // Determines whether to generate a BuildConfig class.
    buildConfig = true
    // Determines whether to support View Binding.
    // Note that the viewBinding.enabled property is now deprecated.
    viewBinding = false
    // Determines whether to support Data Binding.
    // Note that the dataBinding.enabled property is now deprecated.
    dataBinding = false
    // Determines whether to generate binder classes for your AIDL files.
    aidl = true
    // Determines whether to support RenderScript.
    renderScript = true
    // Determines whether to support injecting custom variables into the module’s R class.
    resValues = true
    // Determines whether to support shader AOT compilation.
    shaders = true
  }
}

También puedes especificar el parámetro de configuración predeterminado para esas funciones en todos los módulos de un proyecto incluyendo uno o más de los siguientes elementos en el archivo gradle.properties de tu proyecto, como se muestra más abajo. Ten en cuenta que puedes usar el bloque buildFeatures del archivo build.gradle a nivel de módulo para anular la configuración predeterminada de todo el proyecto.

android.defaults.buildfeatures.buildconfig=true
android.defaults.buildfeatures.aidl=true
android.defaults.buildfeatures.renderscript=true
android.defaults.buildfeatures.resvalues=true
android.defaults.buildfeatures.shaders=true

Dependencias entre funciones

En versiones anteriores del complemento de Android para Gradle, todos los módulos de funciones podían depender únicamente del módulo básico de la app. Pero si usas la versión 4.0.0 del complemento de Android para Gradle, puedes incluir un módulo de funciones que depende de otro. Es decir, una función :video puede depender de la función :camera, que depende del módulo básico, como se muestra en la siguiente figura.

Dependencias entre funciones

El módulo de funciones :video depende de la función :camera, que depende del módulo básico :app.

Eso significa que, cuando la app solicita descargar un módulo de funciones, también descarga otros módulos de los que depende. Después de crear módulos de funciones para tu app, puedes declarar una dependencia entre funciones del archivo build.gradle del módulo. Por ejemplo, el módulo :video declara que depende de :camera de la siguiente manera:

// In the build.gradle file of the ':video' module.
dependencies {
  // All feature modules must declare a dependency
  // on the base module.
  implementation project(':app')
  // Declares that this module also depends on the 'camera'
  // feature module.
  implementation project(':camera')
  ...
}
// In the build.gradle file of the ':video' module.
dependencies {
    // All feature modules must declare a dependency
    // on the base module.
    implementation(project(":app"))
    // Declares that this module also depends on the 'camera'
    // feature module.
    implementation(project(":camera"))
    ...
}

Además, debes habilitar la función de dependencia entre funciones en Android Studio (para admitir la función a la hora de editar la configuración de ejecución). Para ello, haz clic en Help > Edit Custom VM Options en la barra de menú y agrega lo siguiente:

-Drundebug.feature.on.feature=true

Metadatos de dependencias

Cuando compilas tu app con el complemento de Android para Gradle 4.0.0 y versiones posteriores, el complemento incluye metadatos que describen las dependencias que se compilan en la app. Cuando subes tu app, Play Console inspecciona esos metadatos para brindarte los siguientes beneficios:

  • Recibir alertas de problemas conocidos con SDKs y dependencias
  • Recibir comentarios prácticos para resolver esos problemas

Los datos se comprimen, se encriptan con una clave de firma de Google Play y se almacenan en el bloque de firma de tu app de lanzamiento. Sin embargo, puedes inspeccionar los metadatos por tu cuenta desde los archivos de compilación intermedios locales que se encuentran en el directorio <project>/<module>/build/outputs/sdk-dependencies/release/sdkDependency.txt.

Si prefieres no compartir esa información, puedes incluir lo siguiente en el archivo build.gradle de tu módulo:

android {
  dependenciesInfo {
      // Disables dependency metadata when building APKs.
      includeInApk = false
      // Disables dependency metadata when building Android App Bundles.
      includeInBundle = false
  }
}
android {
  dependenciesInfo {
      // Disables dependency metadata when building APKs.
      includeInApk = false
      // Disables dependency metadata when building Android App Bundles.
      includeInBundle = false
  }
}

Cómo importar bibliotecas nativas desde dependencias de AAR

Ahora puedes importar bibliotecas C/C++ desde las dependencias AAR de tu app. Si sigues los pasos de configuración que se describen a continuación, Gradle hará que esas bibliotecas nativas estén disponibles automáticamente para que se puedan usar con tu sistema de compilación nativo externo, como CMake. Ten en cuenta que Gradle solo pone esas bibliotecas a disposición de tu compilación. Para usarlas, deberás configurar tus secuencias de comandos de compilación.

Las bibliotecas se exportan con el formato de paquete Prefab.

Cada dependencia puede exponer como máximo un paquete Prefab, que comprenda uno o más módulos. Un módulo de Prefab es una biblioteca única, que puede ser una biblioteca compartida, estática o solo de encabezado.

Por lo general, el nombre del paquete coincide con el del artefacto de Maven, y el nombre del módulo con el de la biblioteca, aunque no siempre es así. Debido a que necesitas conocer los nombres del paquete y del módulo de las bibliotecas, es posible que debas consultar la documentación de la dependencia para determinar cuáles son esos nombres.

Cómo configurar un sistema de compilación nativo externo

Para ver los pasos que debes seguir, haz clic en el sistema de compilación nativo externo que tienes pensado usar.

Cada una de las dependencias AAR de tu app que incluye código nativo expone un archivo Android.mk que debes importar a tu proyecto ndk-build. Importa ese archivo con el comando import&endash;module, que busca las rutas de acceso que especificas con la propiedad import&endash;add&endash;path de tu proyecto ndk-build. Por ejemplo, si la aplicación define libapp.so y usa curl, debes incluir lo siguiente en tu archivo Android.mk:

  1. Para CMake:

    add_library(app SHARED app.cpp)

    # Add these two lines. find_package(curl REQUIRED CONFIG) target_link_libraries(app curl::curl)

  2. Para ndk-build:

    include $(CLEAR_VARS)
    LOCAL_MODULE := libapp
    LOCAL_SRC_FILES := app.cpp
    # Link libcurl from the curl AAR.
    LOCAL_SHARED_LIBRARIES := curl
    include $(BUILD_SHARED_LIBRARY)

    # If you don't expect that your project will be built using versions of the NDK # older than r21, you can omit this block. ifneq ($(call ndk-major-at-least,21),true) $(call import-add-path,$(NDK_GRADLE_INJECTED_IMPORT_PATH)) endif

    # Import all modules that are included in the curl AAR. $(call import-module,prefab/curl)

Las dependencias nativas incluidas en un AAR se exponen a tu proyecto CMake mediante la variable CMAKE_FIND_ROOT_PATH{: .external}. Gradle establecerá automáticamente ese valor cuando se invoque CMake, por lo que, si tu sistema de compilación modifica la variable, asegúrate de adjuntarla en lugar de asignarla.

Cada dependencia expone un paquete de config-file{: .external} a tu compilación de CMake, que importas con el comando find_package{: .external}. Ese comando busca paquetes de config-file que coincidan con el nombre y la versión del paquete específico, y expone los destinos que define para su uso en tu compilación. Por ejemplo, si tu aplicación define libapp.so y usa curl, debes incluir lo siguiente en tu archivo CMakeLists.txt:


add_library(app SHARED app.cpp)

# Add these two lines. find_package(curl REQUIRED CONFIG) target_link_libraries(app curl::curl)

Ahora puedes especificar #include "curl/curl.h" en app.cpp. Cuando compilas un proyecto, tu sistema de compilación nativo externo vincula automáticamente libapp.so con libcurl.so y los paquetes libcurl.so del APK o paquete de aplicación. Para obtener más información, consulta el ejemplo de prefab de curl{: .external}.

Cambios en el comportamiento

Cuando uses esta versión del complemento, es posible que ocurran los siguientes cambios de comportamiento.

Actualizaciones de configuración de firmas v1/v2

Se modificó el comportamiento de las configuraciones de firma de apps en el bloque signingConfig de la siguiente manera:

Firma v1

  • Si v1SigningEnabled está habilitado explícitamente, AGP realiza la firma de apps v1.
  • Si el usuario inhabilita explícitamente v1SigningEnabled, no se realiza la firma de apps v1.
  • Si el usuario no habilitó explícitamente la firma v1, se puede inhabilitar de manera automática en función de minSdk y targetSdk.

Firma v2

  • Si v2SigningEnabled está habilitado explícitamente, AGP realiza la firma de apps v2.
  • Si el usuario inhabilita explícitamente v2SigningEnabled, no se realiza la firma de apps v2.
  • Si el usuario no habilitó explícitamente la firma v2, se puede inhabilitar de manera automática en función de targetSdk.

Estos cambios permiten que AGP optimice las compilaciones mediante la inhabilitación del mecanismo de firma en función de si el usuario habilitó explícitamente estas marcas. Antes de esta versión, era posible que v1Signing se inhabilitara incluso cuando se habilitaba de manera explícita, lo que podría ser confuso.

Se quitaron los complementos de Android para Gradle feature y instantapp

En el complemento de Android para Gradle 3.6.0, el complemento de Feature (com.android.feature) y el complemento de Apps instantáneas (com.android.instantapp) dejaron de estar disponibles, y fueron reemplazados por el complemento de Dynamic Feature (com.android.dynamic-feature) para compilar y empaquetar las apps instantáneas mediante Android App Bundles.

En el complemento de Android para Gradle 4.0.0 y versiones posteriores, se quitaron por completo esos complementos obsoletos. Por lo tanto, para usar el complemento de Android para Gradle más reciente, debes migrar tu app instantánea de modo que sea compatible con Android App Bundles. Si migras tus apps instantáneas, puedes aprovechar los beneficios de los paquetes de aplicaciones y simplificar el diseño modular de tu app.

Nota: Para abrir proyectos que usan los complementos borrados en Android Studio 4.0 y versiones posteriores, el proyecto debe usar el complemento de Android para Gradle 3.6.0 o versiones anteriores.

Se quitó la función de procesamiento de anotaciones independiente

Se quitó la posibilidad de separar el procesamiento de anotaciones en una tarea exclusiva. Esa opción se usa para mantener la compilación incremental de Java cuando se utilizan procesadores de anotaciones no incrementales en proyectos solo de Java. Se habilitó mediante la configuración de android.enableSeparateAnnotationProcessing en true en el archivo gradle.properties, que ya no funciona.

En su lugar, debes migrar al uso de procesadores de anotaciones incrementales para mejorar el rendimiento de la compilación.

Se dio de baja includeCompileClasspath

El complemento de Android para Gradle ya no comprueba ni incluye procesadores de anotaciones que declares en la ruta de clase de la compilación, y la propiedad DSL annotationProcessorOptions.includeCompileClasspath ya no tiene ningún efecto. Si incluyes procesadores de anotaciones en la ruta de clase de la compilación, es posible que obtengas el siguiente error:

Error: Annotation processors must be explicitly declared now.

Para resolver ese problema, debes incluir procesadores de anotaciones en tus archivos build.gradle mediante la configuración de dependencia annotationProcessor. Para obtener más información, consulta Cómo agregar procesadores de anotaciones.

Empaquetado automático de dependencias compiladas previamente que usa CMake

Las versiones anteriores del complemento de Android para Gradle requerían que empaquetaras de forma explícita las bibliotecas compiladas previamente que usaba tu compilación nativa externa de CMake con jniLibs. Es posible que tengas bibliotecas en el directorio src/main/jniLibs de tu módulo o, quizás, en otro directorio configurado de tu archivo build.gradle:

sourceSets {
  main {
    // The libs directory contains prebuilt libraries that are used by the
    // app's library defined in CMakeLists.txt via an IMPORTED target.
    jniLibs.srcDirs = ['libs']
  }
}
sourceSets {
  main {
    // The libs directory contains prebuilt libraries that are used by the
    // app's library defined in CMakeLists.txt via an IMPORTED target.
    jniLibs.setSrcDirs(listOf("libs"))
  }
}

Con el complemento de Android para Gradle 4.0, la configuración anterior ya no es necesaria y generará una falla de compilación:

* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
  > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
    > More than one file was found with OS independent path 'lib/x86/libprebuilt.so'

La compilación nativa externa ahora empaqueta automáticamente esas bibliotecas, de modo que hacerlo de forma explícita con jniLibs genera una duplicación. Para evitar el error de compilación, mueve la biblioteca compilada con anterioridad a una ubicación fuera de jniLibs o quita la configuración jniLibs del archivo build.gradle.

Errores conocidos

En esta sección, se describen los problemas conocidos presentes en el complemento de Android para Gradle 4.0.0.

Condición de carrera en el mecanismo de trabajador de Gradle

Los cambios en el complemento de Android para Gradle 4.0 pueden activar una condición de carrera en Gradle cuando se ejecuta con &endash;&endash;no&endash;daemon y las versiones de Gradle 6.3 o anteriores, lo que hace que las compilaciones se bloqueen después de que termine el proceso de compilación.

Ese error se corregirá en Gradle 6.4.