Bazel 教程:构建 Android 应用

注意:使用 Bazel 构建 Android 应用存在已知限制。 请访问 Github 团队 Android 热点列表,查看已知问题列表。虽然 Bazel 团队和开源软件 (OSS) 贡献者积极致力于解决已知问题,但用户应注意,Android Studio 未正式支持 Bazel 项目。

本教程介绍了如何使用 Bazel 构建简单的 Android 应用。

Bazel 支持使用 Android 规则构建 Android 应用。

本教程面向 Windows、macOS 和 Linux 用户,不需要 Bazel 或 Android 应用开发经验。在本教程中,您无需编写任何 Android 代码。

学习内容

在本教程中,您将学习如何:

  • 安装 Bazel 和 Android Studio,并 下载示例项目,以设置环境。
  • 设置 Bazel 工作区,其中包含应用的源代码 和用于标识工作区目录顶层的 WORKSPACE 文件。
  • 更新 WORKSPACE 文件,使其包含对所需 外部依赖项(例如 Android SDK)的引用。
  • 创建 BUILD 文件。
  • 使用 Bazel 构建应用。
  • 在 Android 模拟器或实体设备上部署和运行应用。

准备工作

安装 Bazel

在开始本教程之前,请安装以下软件:

  • Bazel。如需安装,请按照安装说明操作。
  • Android Studio 。如需安装,请按照下载 Android Studio的步骤操作。 执行设置向导,下载 SDK 并配置环境。
  • (可选)Git 。使用 git 下载 Android 应用项目。

获取示例项目

对于示例项目,请使用 Bazel 示例代码库中的基本 Android 应用项目。

此应用有一个按钮,点击后会打印问候语:

按钮问候语

图 1。Android 应用按钮问候语。

使用 git 克隆代码库(或直接 下载 ZIP 文件):

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

本教程的示例项目位于 examples/android/tutorial 中。在本教程的其余部分,您将在此目录中执行命令。

查看源文件

查看应用的源文件。

.
├── 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

关键文件和目录如下:

名称 位置
Android 清单文件 src/main/AndroidManifest.xmlsrc/main/java/com/example/bazel/AndroidManifest.xml
Android 源文件 src/main/java/com/example/bazel/MainActivity.javaGreeter.java
资源文件目录 src/main/java/com/example/bazel/res/

使用 Bazel 构建

设置工作区

一个 工作区 是一个目录,其中包含一个或多个软件项目的 源文件,并且其根目录中有一个 WORKSPACE 文件。

WORKSPACE 文件可能为空,也可能包含对构建项目所需的 外部 依赖项 的引用。

首先,运行以下命令以创建空的 WORKSPACE 文件:

操作系统 命令
Linux、macOS touch WORKSPACE
Windows(命令提示符) type nul > WORKSPACE
Windows (PowerShell) New-Item WORKSPACE -ItemType file

运行 Bazel

您现在可以使用以下命令检查 Bazel 是否正常运行:

bazel info workspace

如果 Bazel 打印当前目录的路径,则表示一切正常!如果 WORKSPACE 文件不存在,您可能会看到类似如下的错误消息:

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

与 Android SDK 集成

Bazel 需要运行 Android SDK 构建工具 来构建应用。这意味着,您需要向 WORKSPACE 文件添加一些信息,以便 Bazel 知道在哪里找到这些工具。

将以下行添加到 WORKSPACE 文件中:

android_sdk_repository(name = "androidsdk")

这会使用 ANDROID_HOME 环境变量引用的路径中的 Android SDK,并自动检测该位置中安装的最高 API 级别和 最新版本的构建工具。

您可以将 ANDROID_HOME 变量设置为 Android SDK 的位置。使用 Android Studio 的 SDK 管理器查找已安装 SDK 的路径。假设 SDK 安装在默认位置,您可以使用以下 命令设置 ANDROID_HOME 变量:

操作系统 命令
Linux export ANDROID_HOME=$HOME/Android/Sdk/
macOS export ANDROID_HOME=$HOME/Library/Android/sdk
Windows(命令提示符) set ANDROID_HOME=%LOCALAPPDATA%\Android\Sdk
Windows (PowerShell) $env:ANDROID_HOME="$env:LOCALAPPDATA\Android\Sdk"

上述命令仅为当前 shell 会话设置变量。如需使其 永久生效,请运行以下命令:

操作系统 命令
Linux echo "export ANDROID_HOME=$HOME/Android/Sdk/" >> ~/.bashrc
macOS echo "export ANDROID_HOME=$HOME/Library/Android/Sdk/" >> ~/.bashrc
Windows(命令提示符) setx ANDROID_HOME "%LOCALAPPDATA%\Android\Sdk"
Windows (PowerShell) [System.Environment]::SetEnvironmentVariable('ANDROID_HOME', "$env:LOCALAPPDATA\Android\Sdk", [System.EnvironmentVariableTarget]::User)

您还可以通过添加 pathapi_levelbuild_tools_version 属性,明确指定要使用的 Android SDK 的绝对路径、 API 级别和构建工具版本。如果未指定 api_levelbuild_tools_versionandroid_sdk_repository 规则将 使用 SDK 中提供的相应最新版本。您可以指定这些属性的任意 组合,只要它们存在于 SDK 中即可,例如:

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

在 Windows 上,请注意,path 属性必须使用混合样式路径,即 带有正斜杠的 Windows 路径:

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

可选:如果您想将原生代码编译到 Android 应用中,您 还需要下载 Android NDK ,并通过向 WORKSPACE 文件添加以下行来告知 Bazel 在哪里找到它:

android_ndk_repository(name = "androidndk")

android_sdk_repository 类似,Android NDK 的路径默认是从 ANDROID_NDK_HOME 环境变量推断出来的。也可以使用 android_ndk_repository 上的 path 属性明确指定路径。

如需了解详情,请参阅将 Android Native Development Kit 与 Bazel结合使用。

api_level 是 SDK 和 NDK 所面向的 Android API 版本,例如 Android 6.0 为 23,Android 7.1 为 25。如果未 明确设置,api_level 默认使用 android_sdk_repositoryandroid_ndk_repository 的最高可用 API 级别。

无需为 SDK 和 NDK 将 API 级别设置为相同的值。 本页 包含从 Android 版本到 NDK 支持的 API 级别的映射。

创建 BUILD 文件

A BUILD file 描述了一组构建输出(例如来自 aapt 的已编译 Android 资源或来自 javac 的类文件)及其依赖项之间的关系。这些依赖项可以是 工作区中的源文件(Java、C++)或其他构建输出。BUILD 文件 使用一种名为 Starlark 的语言编写。

BUILD 文件是 Bazel 中称为 软件包层次结构的概念的一部分。 软件包层次结构是一种逻辑结构,它覆盖了工作区中的目录 结构。每个 软件包 都是一个 目录(及其子目录),其中包含一组相关的源文件 和一个 BUILD 文件。软件包还包含任何子目录,但不包含 包含自己的 BUILD 文件的子目录。软件包名称是相对于 WORKSPACEBUILD 文件路径。

请注意,Bazel 的软件包层次结构在概念上与 Android 应用目录的 Java 软件包层次结构不同,尽管目录的组织方式可能相同,其中 BUILD 文件 位于此处。

对于本教程中的简单 Android 应用,src/main/ 中的源文件构成一个 Bazel 软件包。更复杂的项目可能包含许多嵌套 软件包。

添加 android_library 规则

一个 BUILD 文件包含 Bazel 的几种不同类型的声明。最重要的类型是 构建规则,它告知 Bazel 如何从一组源文件或其他依赖项构建中间或最终软件输出。Bazel 提供了两个构建规则: android_libraryandroid_binary,您可以使用它们来 构建 Android 应用。

在本教程中,您将首先使用 android_library 规则告知 Bazel 从应用源代码和资源文件构建 Android 库 模块。然后,您将使用 android_binary 规则告知 Bazel 如何构建 Android 应用软件包。

src/main/java/com/example/bazel 目录中创建一个新的 BUILD 文件, 并声明一个新的 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/**"]),
)

android_library 构建规则包含一组属性,用于指定 Bazel 从源文件构建库模块所需的信息。 另请注意,该规则的名称为 greeter_activity。您将在 android_binary 规则中使用此名称作为依赖项来引用该 规则。

添加 android_binary 规则

android_binary 规则会为您的应用构建 Android 应用软件包(.apk 文件)。

src/main/ 目录中创建一个新的 BUILD 文件, 并声明一个新的 android_binary 目标:

src/main/BUILD

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

在这里,deps 属性引用了您添加到上述 BUILD 文件中的 greeter_activity 规则 的输出。这意味着,当 Bazel 构建此规则的 输出时,它会先检查 greeter_activity 库规则的输出是否已构建且为最新版本。如果不是,Bazel 会构建该输出,然后使用该输出构建应用软件包文件。

现在,保存并关闭该文件。

构建应用

尝试构建应用!运行以下命令以构建 android_binary 目标:

bazel build //src/main:app

build 子命令指示 Bazel 构建后面的 目标。目标指定为构建规则的名称,位于 一个 BUILD 文件中,以及相对于工作区 目录的软件包路径。在此示例中,目标为 app,软件包路径为 //src/main/

请注意,有时您可以省略软件包路径或目标名称,具体取决于 命令行中的当前工作目录和目标的名称。 如需详细了解目标标签和路径,请参阅标签

Bazel 将开始构建示例应用。在构建过程中,其输出 将类似于以下内容:

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

找到构建输出

Bazel 会将中间和最终构建操作的输出放在一组 按用户、按工作区输出的目录中。这些目录通过符号链接从项目目录顶层的以下位置链接,其中包含 WORKSPACE

  • bazel-bin 存储二进制可执行文件和其他可运行的构建输出
  • bazel-genfiles 存储由 Bazel 规则生成的中间源文件
  • bazel-out 存储其他类型的构建输出

Bazel 会将使用 android_binary 规则 生成的 Android .apk 文件存储在 bazel-bin/src/main 目录中,其中子目录名称 src/main 派生自 Bazel 软件包的名称。

在命令提示符下,列出此目录的内容并找到 app.apk 文件:

操作系统 命令
Linux、macOS ls bazel-bin/src/main
Windows(命令提示符) dir bazel-bin\src\main
Windows (PowerShell) ls bazel-bin\src\main

运行应用

您现在可以使用 bazel mobile-install 命令从 命令行将应用部署到连接的 Android 设备或模拟器。此命令使用 Android 调试桥 (adb) 与设备通信。您必须按照 Android Debug Bridge 中的说明设置 设备以使用 adb,然后才能进行部署。您 还可以选择在 Android Studio 中包含的 Android 模拟器上安装应用。请确保模拟器在执行以下命令之前正在运行。

输入以下内容:

bazel mobile-install //src/main:app

接下来,找到并启动“Bazel 教程应用”:

Bazel 教程应用

图 2.Bazel 教程应用。

恭喜!您刚刚安装了第一个使用 Bazel 构建的 Android 应用。

请注意,mobile-install 子命令还支持 --incremental 标志,该标志可用于 仅部署自上次部署以来发生更改的应用部分。

它还支持 --start_app 标志,以便在 安装应用后立即启动应用。

深入阅读

如需了解详情,请参阅以下页面:

祝您构建顺利!