Bazel 教學課程:建構 Android 應用程式

注意:使用 Bazel 建構 Android 應用程式時,會遇到一些已知限制。請前往 rules_android 問題頁面,查看已知問題清單。雖然 Bazel 團隊和開放原始碼軟體 (OSS) 貢獻者積極解決已知問題,但使用者應注意,Android Studio 並未正式支援 Bazel 專案。

本教學課程說明如何使用 Bazel 建構簡單的 Android 應用程式。

Bazel 支援使用 Android 規則建構 Android 應用程式。

本教學課程適用於 Windows、macOS 和 Linux 使用者,且不需具備 Bazel 或 Android 應用程式開發經驗。在本教學課程中,您不需要編寫任何 Android 程式碼。

課程內容

在本教學課程中,您將瞭解如何:

  • 安裝 Bazel 和 Android Studio,並下載範例專案,設定環境。
  • 設定 Bazel 工作區,其中包含應用程式的原始碼,以及可識別工作區目錄頂層的 MODULE.bazel 檔案。
  • 更新 MODULE.bazel 檔案,加入必要外部依附元件 (例如 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 建構

設定工作區

工作區是包含一或多個軟體專案來源檔案的目錄,且根目錄中含有 MODULE.bazel 檔案。

MODULE.bazel 檔案可能為空白,也可能包含建構專案所需的外部依附元件參照。

首先,請執行下列指令來建立空白的 MODULE.bazel 檔案:

作業系統 指令
Linux、macOS touch MODULE.bazel
Windows (命令提示字元) type nul > MODULE.bazel
Windows (PowerShell) New-Item MODULE.bazel -ItemType file

執行 Bazel

現在可以使用下列指令,檢查 Bazel 是否正常運作:

bazel info workspace

如果 Bazel 列印目前目錄的路徑,就表示一切正常!如果 MODULE.bazel檔案不存在,您可能會看到類似以下的錯誤訊息:

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

與 Android SDK 整合

Bazel 需要執行 Android SDK 建構工具來建構應用程式。因此,您需要在 MODULE.bazel 檔案中新增一些資訊,讓 Bazel 知道這些工具的位置。

MODULE.bazel 檔案中新增下列程式碼:

bazel_dep(name = "rules_android", version = "0.6.6")

remote_android_extensions = use_extension(
    "@rules_android//bzlmod_extensions:android_extensions.bzl",
    "remote_android_tools_extensions")
use_repo(remote_android_extensions, "android_tools")

android_sdk_repository_extension = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension")
use_repo(android_sdk_repository_extension, "androidsdk")

這會使用 ANDROID_HOME 環境變數參照路徑中的 Android SDK,並自動偵測該位置安裝的最高 API 級別和最新版建構工具。

您可以將 ANDROID_HOME 變數設為 Android SDK 的位置。使用 Android Studio 的 SDK Manager 找出已安裝 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"

上述指令只會為目前的殼層工作階段設定變數。如要永久啟用這些設定,請執行下列指令:

作業系統 指令
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)

選用:如要將原生程式碼編譯至 Android 應用程式,您也需要下載 Android NDK,並在 MODULE.bazel 檔案中新增下列程式碼行,使用 rules_android_ndk

bazel_dep(name = "rules_android_ndk", version = "0.1.3")

詳情請參閱「將 Android Native Development Kit 與 Bazel 搭配使用」。

SDK 和 NDK 的 API 級別不必設為相同值。 本頁面包含 Android 版本與 NDK 支援 API 級別的對應關係。

建立 BUILD 檔案

BUILD 檔案會說明一組建構輸出內容 (例如來自 aapt 的已編譯 Android 資源,或來自 javac 的類別檔案) 及其依附元件之間的關係。這些依附元件可能是工作區中的來源檔案 (Java、C++) 或其他建構輸出內容。BUILD 檔案是以 Starlark 語言編寫。

BUILD 檔案是 Bazel 中稱為「套件階層」的概念之一。套件階層是邏輯結構,會覆蓋工作區中的目錄結構。每個「套件」都是目錄 (及其子目錄),內含一組相關的來源檔案和 BUILD 檔案。套件也包含任何子目錄,但含有專屬 BUILD 檔案的子目錄除外。套件名稱是相對於 MODULE.bazel 檔案的 BUILD 檔案路徑。

請注意,Bazel 的套件階層在概念上與 Android 應用程式目錄的 Java 套件階層不同,儘管目錄的組織方式可能相同,但 BUILD 檔案位於 Android 應用程式目錄中。

在本教學課程中,簡單的 Android 應用程式的來源檔案包含單一 Bazel 套件。src/main/較複雜的專案可能會有許多巢狀封裝。

新增 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

load("@rules_android//rules:rules.bzl", "android_library")

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

load("@rules_android//rules:rules.bzl", "android_binary")

android_binary(
    name = "app",
    manifest = "//src/main/java/com/example/bazel: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 會將中繼和最終建構作業的輸出內容,放在一組使用者專屬的工作區輸出目錄中。這些目錄是從專案目錄頂層的下列位置進行符號連結,其中 MODULE.bazel 檔案位於:

  • 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 Debug Bridge (adb) 與裝置通訊。您必須先按照「Android Debug Bridge」一文的說明設定裝置,才能使用 adb 部署應用程式。您也可以選擇在 Android Studio 隨附的 Android 模擬器上安裝應用程式。請先確認模擬器正在執行,再執行下列指令。

輸入下列指令:

bazel mobile-install //src/main:app \
  --mode=skylark \
  --mobile_install_aspect=@rules_android//mobile_install:mi.bzl \
  --mobile_install_supported_rules=android_binary \
  --java_runtime_version=17 \
  --java_language_version=17 \
  --tool_java_runtime_version=17 \
  --tool_java_language_version=17

請注意,行動裝置安裝所需的額外標記可以新增至專案的 bazelrc 檔案。從 Bazel 8.4.0 以上版本開始,不再需要行動裝置安裝專屬標記 (--mode--mobile_install*)。視工作區的 Java 設定而定,您可能需要各種 Java 語言和執行階段版本標記。行動裝置安裝子工具的語言和執行階段層級必須為 17 以上。

現在「Bazel Tutorial App」應該會自動安裝並啟動:

Bazel 教學課程應用程式

圖 2. Bazel 教學課程應用程式。

恭喜!您剛安裝了第一個以 Bazel 建構的 Android 應用程式。

延伸閱讀

詳情請參閱下列頁面:

盡情享受建構樂趣吧!