Instructivo de Bazel: Compila una app para Android

Informar un problema Ver fuente

Nota: Existen limitaciones conocidas en cuanto al uso de Bazel para compilar apps para Android. Visita la hotlist de equipo-Android de GitHub para ver la lista de problemas conocidos. Si bien el equipo de Bazel y los colaboradores de software de código abierto (OSS) trabajan activamente para abordar problemas conocidos, los usuarios deben tener en cuenta que Android Studio no admite oficialmente proyectos de Bazel.

En este instructivo, se explica cómo compilar una app para Android simple con Bazel.

Bazel admite la compilación de apps para Android mediante las reglas de Android.

Este instructivo está dirigido a usuarios de Windows, macOS y Linux, y no requiere experiencia en el desarrollo de apps para Android o Bazel. No es necesario que escribas ningún código de Android en este instructivo.

Qué aprenderás

En este instructivo, aprenderás a hacer lo siguiente:

  • Instala Bazel y Android Studio para configurar tu entorno, y descarga el proyecto de muestra.
  • Configura un lugar de trabajo de Bazel que contenga el código fuente de la app y un archivo WORKSPACE que identifique el nivel superior del directorio del lugar de trabajo.
  • Actualiza el archivo WORKSPACE para que incluya referencias a las dependencias externas requeridas, como el SDK de Android.
  • Crea un archivo BUILD.
  • Compila la app con Bazel.
  • Implementa y ejecuta la app en un Android Emulator o un dispositivo físico.

Antes de comenzar

Instala Bazel

Antes de comenzar el instructivo, instala el siguiente software:

  • Bazel. Para instalarlo, sigue las instrucciones de instalación.
  • Android Studio Para ello, sigue los pasos para descargar Android Studio. Ejecuta el asistente de configuración para descargar el SDK y configurar tu entorno.
  • (Opcional) Git. Usa git para descargar el proyecto de la app para Android.

Obtén el proyecto de muestra

Para el proyecto de muestra, usa un proyecto básico de app para Android en el repositorio de ejemplos de Bazel.

Esta app tiene un solo botón que imprime un saludo cuando se hace clic en él:

Saludo de botón

Figura 1: Saludo del botón de la app para Android.

Clona el repositorio con git (o descarga el archivo ZIP directamente):

git clone https://github.com/bazelbuild/examples

El proyecto de muestra para este instructivo se encuentra en examples/android/tutorial. Durante el resto del instructivo, ejecutarás comandos en este directorio.

Revisa los archivos fuente

Observa los archivos fuente de la app.

.
├── README.md
└── src
    └── main
        ├── AndroidManifest.xml
        └── java
            └── com
                └── example
                    └── bazel
                        ├── AndroidManifest.xml
                        ├── Greeter.java
                        ├── MainActivity.java
                        └── res
                            ├── layout
                            │   └── activity_main.xml
                            └── values
                                ├── colors.xml
                                └── strings.xml

Los archivos y directorios clave son los siguientes:

Nombre Location
Archivos de manifiesto de Android src/main/AndroidManifest.xml y src/main/java/com/example/bazel/AndroidManifest.xml
Archivos de origen de Android src/main/java/com/example/bazel/MainActivity.java y Greeter.java
Directorio de archivos de recursos src/main/java/com/example/bazel/res/

Compila con Bazel

Cómo configurar el espacio de trabajo

Un lugar de trabajo es un directorio que contiene los archivos de origen para uno o más proyectos de software y que tiene un archivo WORKSPACE en su raíz.

El archivo WORKSPACE puede estar vacío o contener referencias a dependencias externas necesarias para compilar tu proyecto.

Primero, ejecuta el siguiente comando para crear un archivo WORKSPACE vacío:

SO Comando
Linux y macOS touch WORKSPACE
Windows (Símbolo del sistema) type nul > WORKSPACE
Windows (PowerShell) New-Item WORKSPACE -ItemType file

Ejecuta Bazel

Ahora puedes verificar si Bazel se ejecuta de forma correcta con el siguiente comando:

bazel info workspace

Si Bazel imprime la ruta de acceso del directorio actual, no necesitas hacer nada más. Si el archivo WORKSPACE no existe, es posible que veas un mensaje de error como el siguiente:

ERROR: The 'info' command is only supported from within a workspace.

Cómo realizar la integración con el SDK de Android

Bazel necesita ejecutar las herramientas de compilación del SDK de Android para compilar la app. Esto significa que debes agregar información a tu archivo WORKSPACE para que Bazel sepa dónde encontrarlas.

Agrega la siguiente línea a tu archivo WORKSPACE:

android_sdk_repository(name = "androidsdk")

De esta manera, se usará el SDK de Android en la ruta a la que hace referencia la variable de entorno ANDROID_HOME y se detectará automáticamente el nivel de API más alto y la versión más reciente de las herramientas de compilación instaladas en esa ubicación.

Puedes configurar la variable ANDROID_HOME en la ubicación del SDK de Android. Busca la ruta de acceso al SDK instalado con SDK Manager de Android Studio. Si suponemos que el SDK está instalado en ubicaciones predeterminadas, puedes usar los siguientes comandos para configurar la variable ANDROID_HOME:

SO Comando
Linux export ANDROID_HOME=$HOME/Android/Sdk/
macOS export ANDROID_HOME=$HOME/Library/Android/sdk
Windows (Símbolo del sistema) set ANDROID_HOME=%LOCALAPPDATA%\Android\Sdk
Windows (PowerShell) $env:ANDROID_HOME="$env:LOCALAPPDATA\Android\Sdk"

Los comandos anteriores establecen la variable solo para la sesión de shell actual. Para hacerlos permanentes, ejecuta los siguientes comandos:

SO Comando
Linux echo "export ANDROID_HOME=$HOME/Android/Sdk/" >> ~/.bashrc
macOS echo "export ANDROID_HOME=$HOME/Library/Android/Sdk/" >> ~/.bashrc
Windows (Símbolo del sistema) setx ANDROID_HOME "%LOCALAPPDATA%\Android\Sdk"
Windows (PowerShell) [System.Environment]::SetEnvironmentVariable('ANDROID_HOME', "$env:LOCALAPPDATA\Android\Sdk", [System.EnvironmentVariableTarget]::User)

También puedes especificar de forma explícita la ruta de acceso absoluta del SDK de Android, el nivel de API y la versión de las herramientas de compilación que se usarán. Para ello, incluye los atributos path, api_level y build_tools_version. Si no se especifican api_level ni build_tools_version, la regla android_sdk_repository usará la última versión disponible en el SDK. Puedes especificar cualquier combinación de estos atributos, siempre que estén presentes en el SDK. Por ejemplo:

android_sdk_repository(
    name = "androidsdk",
    path = "/path/to/Android/sdk",
    api_level = 25,
    build_tools_version = "30.0.3"
)

En Windows, ten en cuenta que el atributo path debe usar la ruta de acceso de estilo mixto, es decir, una ruta de Windows con barras diagonales:

android_sdk_repository(
    name = "androidsdk",
    path = "c:/path/to/Android/sdk",
)

Opcional: Si quieres compilar código nativo en tu app para Android, también debes descargar el NDK de Android y, luego, indicarle a Bazel dónde encontrarlo agregando la siguiente línea al archivo WORKSPACE:

android_ndk_repository(name = "androidndk")

Al igual que android_sdk_repository, la ruta de acceso al NDK de Android se infiere de la variable de entorno ANDROID_NDK_HOME de forma predeterminada. La ruta también se puede especificar de forma explícita con un atributo path en android_ndk_repository.

Para obtener más información, consulta Cómo usar el kit de desarrollo nativo de Android con Bazel.

api_level es la versión de la API de Android a la que se orientan el SDK y el NDK; por ejemplo, 23 para Android 6.0 y 25 para Android 7.1. Si no se configura de forma explícita, api_level usa, de forma predeterminada, el nivel de API más alto disponible para android_sdk_repository y android_ndk_repository.

No es necesario configurar los niveles de API con el mismo valor para el SDK y el NDK. Esta página contiene un mapa desde las versiones de Android hasta los niveles de API compatibles con el NDK.

Crea un archivo BUILD

Un archivo BUILD describe la relación entre un conjunto de resultados de compilación, como recursos de Android compilados de aapt o archivos de clase de javac, y sus dependencias. Estas dependencias pueden ser archivos de origen (Java, C++) en tu lugar de trabajo o en otros resultados de compilación. Los archivos BUILD se escriben en un lenguaje llamado Starlark.

Los archivos BUILD forman parte de un concepto en Bazel conocido como jerarquía de paquetes. La jerarquía de paquetes es una estructura lógica que se superpone con la estructura del directorio en tu lugar de trabajo. Cada paquete es un directorio (y sus subdirectorios) que contiene un conjunto relacionado de archivos de origen y un archivo BUILD. El paquete también incluye cualquier subdirectorio, excepto los que contienen su propio archivo BUILD. El nombre del paquete es la ruta al archivo BUILD relacionado con WORKSPACE.

Ten en cuenta que la jerarquía de paquetes de Bazel es conceptualmente diferente de la jerarquía de paquetes de Java del directorio de tu app para Android en la que se encuentra el archivo BUILD, aunque los directorios pueden estar organizados de forma idéntica.

En la app para Android simple de este instructivo, los archivos de origen en src/main/ componen un solo paquete de Bazel. Un proyecto más complejo puede tener muchos paquetes anidados.

Cómo agregar una regla android_library

Un archivo BUILD contiene varios tipos diferentes de declaraciones para Bazel. El tipo más importante es la regla de compilación, que le indica a Bazel cómo compilar una salida de software intermedia o final a partir de un conjunto de archivos fuente u otras dependencias. Bazel proporciona dos reglas de compilación, android_library y android_binary, que puedes usar a fin de compilar una app para Android.

En este instructivo, primero usarás la regla android_library para indicarle a Bazel que compile un módulo de biblioteca de Android a partir del código fuente y los archivos de recursos de la app. Luego, usarás la regla android_binary para indicarle a Bazel cómo compilar el paquete de aplicación para Android.

Crea un nuevo archivo BUILD en el directorio src/main/java/com/example/bazel y declara un nuevo destino android_library:

src/main/java/com/example/bazel/BUILD:

package(
    default_visibility = ["//src:__subpackages__"],
)

android_library(
    name = "greeter_activity",
    srcs = [
        "Greeter.java",
        "MainActivity.java",
    ],
    manifest = "AndroidManifest.xml",
    resource_files = glob(["res/**"]),
)

La regla de compilación android_library contiene un conjunto de atributos que especifican la información que Bazel necesita para compilar un módulo de biblioteca a partir de los archivos de origen. Ten en cuenta también que el nombre de la regla es greeter_activity. Usarás este nombre como dependencia en la regla android_binary para hacer referencia a la regla.

Agrega una regla android_binary

La regla android_binary compila el paquete de aplicación para Android (archivo .apk) de la app.

Crea un nuevo archivo BUILD en el directorio src/main/ y declara un nuevo destino android_binary:

src/main/BUILD:

android_binary(
    name = "app",
    manifest = "AndroidManifest.xml",
    deps = ["//src/main/java/com/example/bazel:greeter_activity"],
)

Aquí, el atributo deps hace referencia al resultado de la regla greeter_activity que agregaste al archivo BUILD anterior. Esto significa que, cuando Bazel compila el resultado de esta regla, primero verifica si el resultado de la regla de la biblioteca greeter_activity se compiló y está actualizado. De lo contrario, Bazel la compila y, luego, usa ese resultado para compilar el archivo del paquete de la aplicación.

Ahora guarda y cierra el archivo.

Compila la app

Intenta compilar la app. Ejecuta el siguiente comando para compilar el destino android_binary:

bazel build //src/main:app

El subcomando build le indica a Bazel que compile el destino que sigue. El destino se especifica como el nombre de una regla de compilación dentro de un archivo BUILD, junto con la ruta del paquete en relación con el directorio del lugar de trabajo. Para este ejemplo, el destino es app y la ruta del paquete es //src/main/.

Ten en cuenta que, a veces, puedes omitir la ruta de acceso del paquete o el nombre del destino, según tu directorio de trabajo actual en la línea de comandos y el nombre del destino. Para obtener más detalles sobre las etiquetas de destino y las rutas, consulta Etiquetas.

Bazel comenzará a compilar la app de ejemplo. Durante el proceso de compilación, el resultado será similar al siguiente:

INFO: Analysed target //src/main:app (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //src/main:app up-to-date:
  bazel-bin/src/main/app_deploy.jar
  bazel-bin/src/main/app_unsigned.apk
  bazel-bin/src/main/app.apk

Ubica los resultados de la compilación

Bazel coloca los resultados de las operaciones de compilación intermedias y finales en un conjunto de directorios de salida por usuario y por lugar de trabajo. Estos directorios tienen un symlink desde las siguientes ubicaciones en el nivel superior del directorio del proyecto, donde WORKSPACE es:

  • bazel-bin almacena ejecutables binarios y otros resultados de compilación ejecutables
  • bazel-genfiles almacena archivos fuente intermedios que generan las reglas de Bazel.
  • bazel-out almacena otros tipos de resultados de compilación

Bazel almacena el archivo .apk de Android generado con la regla android_binary en el directorio bazel-bin/src/main, en el que el nombre del subdirectorio src/main se deriva del nombre del paquete de Bazel.

En el símbolo del sistema, muestra el contenido de este directorio y busca el archivo app.apk:

SO Comando
Linux y macOS ls bazel-bin/src/main
Windows (Símbolo del sistema) dir bazel-bin\src\main
Windows (PowerShell) ls bazel-bin\src\main

Ejecuta la app

Ahora puedes implementar la app en un emulador o dispositivo Android conectado desde la línea de comandos con el comando bazel mobile-install. Este comando usa Android Debug Bridge (adb) para comunicarse con el dispositivo. Sigue las instrucciones de Android Debug Bridge antes de la implementación y configura tu dispositivo para que use adb. También puedes instalar la app en el emulador de Android que se incluye en Android Studio. Asegúrate de que se esté ejecutando el emulador antes de ejecutar el siguiente comando.

Ingresa el siguiente comando:

bazel mobile-install //src/main:app

A continuación, busca e inicia la "app de instructivo de Bazel":

App de instructivo de Bazel

Figura 2: App de instructivo de Bazel.

¡Felicitaciones! Acabas de instalar tu primera app para Android compilada con Bazel.

Ten en cuenta que el subcomando mobile-install también admite la marca --incremental que se puede usar para implementar solo las partes de la app que cambiaron desde la última implementación.

También admite la marca --start_app para iniciar la app inmediatamente después de instalarla.

Lecturas adicionales

Para obtener más información, consulta las siguientes páginas:

¡Feliz compilación!