各位戰士,歡迎來到第二十八天的戰場。昨天,我們成功地為應用程式建立了性能基準測試,我們現在擁有一把可以精準測量啟動速度和滾動流暢度的「卡尺」。
這把卡尺很棒,但如果它只放在工具箱裡,等到我們想起來的時候才拿出來用,那麼性能的劣化仍然會在我們不經意間發生。我們需要一個自動化的哨兵,一個在每次有新程式碼試圖進入我們的程式庫時,都強制用這把卡尺測量一遍的「邊境檢查官」。
這個自動化的邊境,就是我們的 CI/CD (持續整合/持續部署) 流程。今天的任務,就是將我們的 Macrobenchmark 測試整合到主流的 CI 平台——GitHub Actions 中,打造一個銅牆鐵壁般的性能迴歸 (Regression) 防護網。
在 CI 伺服器上運行基準測試,比運行普通單元測試要複雜得多。主要挑戰在於:
Macrobenchmark 需要一個真實的 Android 執行環境。
我們的 CI 伺服器通常只是一個運行在雲端的 Linux 或 macOS 虛擬機。我們必須先在這台虛擬機上,成功地啟動一個 Android 模擬器 (Emulator),然後才能在模擬器上安裝並運行我們的測試。
幸運的是,隨著工具鏈的成熟,現在已有現成的 GitHub Actions 套件能為我們處理掉大部分複雜的設定。
我們將使用 GitHub Actions 作為我們的 CI 平台。而解決環境挑戰的關鍵武器,是一個名為 ReactiveCircus/android-emulator-runner
的開源 Action,它能幫我們在 GitHub 的虛擬機中自動下載、設定並啟動一個 Android 模擬器。
我們的 CI 工作流程 (Workflow) 將執行以下步驟:
main
分支,或有新的合併請求 (Pull Request) 提交時,自動觸發。android-emulator-runner
Action 來啟動一個無頭 (Headless) 的 Android 模擬器。:benchmark
模組中的所有測試。在你的專案根目錄下,建立 .github/workflows/macrobenchmark.yml
檔案,並貼上以下內容:
name: Run Macrobenchmarks
# 觸發條件
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
benchmark:
# 模擬器在 macOS 虛擬機上通常有更好的硬體加速支援
runs-on: macos-latest
steps:
# 步驟一:Checkout 程式碼
- name: Checkout code
uses: actions/checkout@v4
# 步驟二:設定 Java 環境
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
# 步驟三:設定 Gradle 快取 (加速建構)
- name: Gradle cache
uses: gradle/gradle-build-action@v3
# 步驟四:設定 AVD 快取 (極大地加速模擬器啟動)
- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/sdk/system-images/android-33/google_apis/x86_64/*
key: avd-33
# 步驟五:啟動模擬器 (只有在快取未命中時才需要完整創建)
- name: Create AVD and run emulator
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
target: google_apis
arch: x86_64
profile: Nexus 6
script: echo "Emulator started"
# 步驟六:執行 Macrobenchmark 測試
- name: Run benchmarks
run: ./gradlew :benchmark:connectedCheck
AVD cache
:這是至關重要的最佳化。第一次運行時,我們會完整創建並啟動模擬器,並將其快取。後續的運行,可以直接從快取中恢復,將準備時間從數分鐘縮短到幾十秒。
android-emulator-runner
:我們在這裡定義了模擬器的規格,例如 API 等級、CPU 架構等。
./gradlew :benchmark:connectedCheck
:這是執行我們基準測試模組的標準 Gradle 指令。它會自動找到連接的設備(也就是我們啟動的模擬器)並在上面運行測試。
將此檔案提交到你的 GitHub 倉庫後,GitHub Actions 就會開始為你站崗。
基礎應用:在最簡單的情況下,它提供了一個「通過/失敗」的信號。如果有人提交的程式碼意外地破壞了測試(例如,移除了某個 View 的 ID 導致測試腳本找不到),CI 會立刻失敗,保護你的主分支。
進階應用:更進階的作法是,將每次運行產生的 JSON 報告儲存為「Artifacts」。然後,你可以設定一個性能預算,例如「冷啟動時間的中位數不得比 main
分支的基準值差 5% 以上」。如果新的提交超過了這個預算,就自動將 CI 標記為失敗。這需要搭配 androidx.benchmark.gradle.plugin
等工具來實現。
今天,我們將性能測試從一次性的手動操作,升級為一個自動化、系統化的防護機制。
我們認識到在 CI 中運行 Benchmark 的核心挑戰是建立 Android 執行環境。
我們學會了使用 GitHub Actions 搭配 android-emulator-runner
來自動化地啟動模擬器並執行測試。
我們建立了一個會在每次提交程式碼時自動運行的性能哨兵,從此告別「憑感覺」和「忘了測」,讓性能監控成為開發流程中不可或缺的一環。
我們的自動化防線已經在本機和 CI 上建立完畢。但是,這一切都還是在「實驗室」環境中。真實的戰場是使用者千奇百怪的手機。明天,我們將學習如何從真實的使用者設備上收集性能數據,請出我們的戰地記者——Firebase Performance Monitoring。
我們明天見!