iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
Mobile Development

Android 性能戰爭:從 Profiler 開始的 30 天優化實錄系列 第 28

# Day 28:【自動化戰爭】在 CI/CD 中運行 Benchmark

  • 分享至 

  • xImage
  •  

各位戰士,歡迎來到第二十八天的戰場。昨天,我們成功地為應用程式建立了性能基準測試,我們現在擁有一把可以精準測量啟動速度和滾動流暢度的「卡尺」。

這把卡尺很棒,但如果它只放在工具箱裡,等到我們想起來的時候才拿出來用,那麼性能的劣化仍然會在我們不經意間發生。我們需要一個自動化的哨兵,一個在每次有新程式碼試圖進入我們的程式庫時,都強制用這把卡尺測量一遍的「邊境檢查官」。

這個自動化的邊境,就是我們的 CI/CD (持續整合/持續部署) 流程。今天的任務,就是將我們的 Macrobenchmark 測試整合到主流的 CI 平台——GitHub Actions 中,打造一個銅牆鐵壁般的性能迴歸 (Regression) 防護網。


CI 中運行 Benchmark 的挑戰

在 CI 伺服器上運行基準測試,比運行普通單元測試要複雜得多。主要挑戰在於:

Macrobenchmark 需要一個真實的 Android 執行環境。

我們的 CI 伺服器通常只是一個運行在雲端的 Linux 或 macOS 虛擬機。我們必須先在這台虛擬機上,成功地啟動一個 Android 模擬器 (Emulator),然後才能在模擬器上安裝並運行我們的測試。

幸運的是,隨著工具鏈的成熟,現在已有現成的 GitHub Actions 套件能為我們處理掉大部分複雜的設定。


武器介紹:GitHub Actions 與 Emulator Runner

我們將使用 GitHub Actions 作為我們的 CI 平台。而解決環境挑戰的關鍵武器,是一個名為 ReactiveCircus/android-emulator-runner 的開源 Action,它能幫我們在 GitHub 的虛擬機中自動下載、設定並啟動一個 Android 模擬器。

自動化作戰計畫

我們的 CI 工作流程 (Workflow) 將執行以下步驟:

  1. 觸發:當有新的程式碼被推送到 main 分支,或有新的合併請求 (Pull Request) 提交時,自動觸發。
  2. 準備環境:CI 伺服器啟動,並 Checkout 最新的程式碼。
  3. 啟動模擬器:使用 android-emulator-runner Action 來啟動一個無頭 (Headless) 的 Android 模擬器。
  4. 執行測試:執行 Gradle 指令,在剛剛啟動的模擬器上運行我們的 :benchmark 模組中的所有測試。
  5. 回報結果:如果測試成功運行,工作流程就標記為「成功」。如果性能嚴重下降(進階設定)或測試失敗,則標記為「失敗」,從而阻止有問題的程式碼被合併。

撰寫你的工作流程檔案

在你的專案根目錄下,建立 .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 指令。它會自動找到連接的設備(也就是我們啟動的模擬器)並在上面運行測試。

如何利用 CI 結果

將此檔案提交到你的 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。

我們明天見!


上一篇
# Day 27:【自動化戰爭】建立性能基準 (Benchmark)
系列文
Android 性能戰爭:從 Profiler 開始的 30 天優化實錄28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言