Administrator
发布于 2026-08-25 / 29 阅读
0
0

系列文章《Android 工程师的 100 篇进阶笔记》第 39 篇:Android CI/CD 实践:GitHub Actions 与 GitLab CI

上一篇聊了启动优化,这篇换个方向——工程效率。CI/CD 不是写代码本身,但它决定了代码从提交到上线的效率和质量。很多团队的 Android CI 还停留在"跑个 lint 就打包"的阶段,这篇聊聊怎么搭一套真正有用的 CI/CD。

Android CI/CD 要做什么

一个完整的 Android CI pipeline 应该包括:

  1. 代码检查:Lint、ktlint/detekt

  2. 编译构建:Debug + Release

  3. 单元测试:JUnit + Robolectric

  4. Instrumentation 测试:UI 自动化(需要模拟器或真机)

  5. 覆盖率报告:JaCoCo / Kover

  6. 打包分发:APK/AAB 上传到内部测试或 Play Console

  7. 安全扫描:依赖漏洞检查

GitHub Actions 方案

基础工作流

# .github/workflows/android-ci.yml
name: Android CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        cache: gradle

    - name: Setup Android SDK
      uses: android-actions/setup-android@v3

    - name: Grant execute permission for gradlew
      run: chmod +x gradlew

    - name: Run ktlint
      run: ./gradlew ktlintCheck

    - name: Run Lint
      run: ./gradlew lintDebug

    - name: Run Unit Tests
      run: ./gradlew testDebugUnitTest

    - name: Build Debug APK
      run: ./gradlew assembleDebug

    - name: Upload APK
      uses: actions/upload-artifact@v4
      with:
        name: app-debug.apk
        path: app/build/outputs/apk/debug/app-debug.apk

Gradle 缓存是加速 CI 的关键。actions/setup-java 的 cache: gradle 选项会缓存 ~/.gradle/caches,第二次构建能省 2-5 分钟。

Release 流水线

  release:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        cache: gradle

    - name: Build Release AAB
      run: ./gradlew bundleRelease
      env:
        SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
        SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
        SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}

    - name: Upload to Play Store
      uses: r0adkll/upload-google-play@v1
      with:
        serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
        packageName: com.example.app
        releaseFiles: app/build/outputs/bundle/release/app-release.aab
        track: internal

签名密钥不要放在仓库里,用 GitHub Secrets 管理。构建时通过环境变量注入。

GitLab CI 方案

# .gitlab-ci.yml
stages:
  - check
  - test
  - build
  - deploy

variables:
  GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.caching=true"

lint:
  stage: check
  image: cimg/android:2024.07
  script:
    - ./gradlew ktlintCheck detekt
  cache:
    key: gradle-cache
    paths:
      - .gradle/
      - build/
      - app/build/

unit_test:
  stage: test
  image: cimg/android:2024.07
  script:
    - ./gradlew testDebugUnitTest
  artifacts:
    reports:
      junit: app/build/test-results/**/TEST-*.xml
    paths:
      - app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
  cache:
    key: gradle-cache
    policy: pull

build_release:
  stage: build
  only:
    - main
  script:
    - ./gradlew bundleRelease
  artifacts:
    paths:
      - app/build/outputs/bundle/release/app-release.aab

GitLab CI 的缓存策略比 GitHub Actions 更灵活,可以指定 policy: pull 只拉不推,适合多阶段流水线。

Instrumentation 测试

需要模拟器跑 UI 测试,是 Android CI 的难点。两种方案:

方案一:GitHub Actions 模拟器

  instrumentation_test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: reactivecircus/android-emulator-runner@v2
      with:
        api-level: 34
        arch: x86_64
        script: ./gradlew connectedAndroidTest

缺点:模拟器启动慢(3-5 分钟),稳定性一般,偶尔会超时。

方案二:Firebase Test Lab

    - name: Run on Firebase Test Lab
      run: |
        gcloud auth activate-service-account --key-file=service-account.json
        gcloud firebase test android run \
          --type instrumentation \
          --app app/build/outputs/apk/debug/app-debug.apk \
          --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
          --device model=Pixel8,version=34,locale=zh_CN,orientation=portrait

Firebase Test Lab 更稳定,支持多设备并行,但有费用。

Gradle 缓存优化

CI 上 Gradle 构建慢,主要是依赖下载和编译缓存。加速手段:

  1. Gradle Build Cache:开启本地和远程缓存

// gradle.properties
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4g
  1. 版本目录(Version Catalog):统一依赖版本,减少解析时间

  2. 按需配置:./gradlew assembleDebug --configuration-cache

  3. 配置缓存(Configuration Cache):Gradle 8+ 支持,减少配置阶段时间,能省 20-40% 构建时间

质量门禁

在 CI 中设置质量门槛,不达标就阻止合并:

    - name: Check coverage
      run: |
        COVERAGE=$(./gradlew jacocoTestReport -q | grep "Total" | awk '{print $NF}')
        if (( $(echo "$COVERAGE < 60" | bc -l) )); then
          echo "Coverage $COVERAGE% is below 60%"
          exit 1
        fi

小结

CI/CD 的核心不是工具选择,而是流程设计。先保证基础流程跑通(lint + test + build),再逐步加质量门禁、自动化分发、性能测试。Gradle 缓存和配置缓存是加速 CI 的关键,别让 CI 成为开发效率的瓶颈。

下一篇聊聊 Android 依赖管理:Version Catalogs 的使用。


评论