用途
该技能面向在 GitHub Actions 中为 Android 应用做部署的场景,重点不在通用 CI,而在于签名、AAB 构建与上架商店。它与其他技能分工:通用 CI 交给 github-actions,应用开发交给 android-development,JVM 测试交给 android-unit-testing,应用内购买(billing)与上传不同,交给 play-billing。
需要先探测项目属于原生(gradlew)还是 Expo/React Native(eas.json),不要在没有必要时把 eas build 和 bundleRelease 混在同一个 job 里。
不可协商的规则
- Play 接收的是 AAB(bundleRelease),不是 APK;APK 只用于 sideload 或 Firebase App Distribution。
- Keystore 与密码只能放在 GitHub Secrets,绝不能把 .jks / .keystore 提交进 git。
- Play App Signing 开启时,CI 使用 upload key。
- Play 的 service account(JSON)放在 secret 中,遵循最小权限(Release to testing / production)。
- versionCode 必须确定(使用版本化文件或 github.run_number,但要记录为单一来源)。
- 自动 CI 使用 internal(或 alpha)轨道;production 需配合 environment: production 与 reviewer。
使用方式
原生项目 CI 示例
jobs:
test:
runs-on: ubuntu-latest
permissions: { contents: read }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17" # 项目对应的 JDK
cache: gradle
- run: chmod +x gradlew
- run: ./gradlew --no-daemon lintDebug testDebugUnitTest
gradlew wrapper 是必需的,且使用与 compileOptions 相同的 JDK。插桩测试(connectedCheck / 模拟器)不放在默认 PR 流程中,应使用 Firebase Test Lab 或 workflow_dispatch 的 job(参见 android-instrumented-testing)。Gradle 缓存通过 setup-java 的 cache: gradle 实现。
签名
典型 secrets 包括 ANDROID_KEYSTORE_BASE64、ANDROID_KEYSTORE_PASSWORD、ANDROID_KEY_ALIAS、ANDROID_KEY_PASSWORD。在 release job 中解码 keystore(base64 -d),若写入磁盘需在结束时删除。release 的 signingConfigs 读取环境变量(ORG_GRADLE_PROJECT_… 或在 runner 上生成的 gradle.properties)。debug signing 只用于 debug,release 绝不使用 signingConfig signingConfigs.debug。
发布与 Play 示例
deploy-play:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: internal # 或 production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: "17", cache: gradle }
- run: ./gradlew --no-daemon bundleRelease
# Fastlane supply 或 Play Publisher action
可使用 Fastlane supply / upload_to_play_store 或仓库已有的 Play Publisher action。service account JSON 通过 PLAY_SERVICE_ACCOUNT_JSON 提供。轨道顺序为 internal → alpha/beta → production;可在 Console 中提升,或使用显式 lane,第一个 workflow 不要直接跳到 production。若团队对发布说明做版本管理,在 fastlane/metadata 中提供 en-US/pt-BR changelog。除上传商店外,还应上传 .aab artifact(upload-artifact),保留期设短。
版本管理
versionName 面向用户可见(产品的 semver / calver)。versionCode 必须始终递增。Play 发生冲突时 CI 应失败,而不是使用 --force。Flavors(prod/staging)需使用正确的 bundle 与 package name,不要把 debug 发布到 Play。
Expo / React Native
使用 EXPO_TOKEN(或项目支持时用 Expo OIDC)。通过 eas build --platform android --profile production 与 eas submit --platform android,或下载 AAB 后走同一套 supply 流程。eas.json 的 production profile 应先指向同一个 internal 轨道。如果二进制由 EAS 负责,不要在 Expo 根目录运行 gradlew。
反模式
- 以“仅为 CI”为由提交 keystore
- 把 APK 上传 Play Store
- 没有 signingConfig 的 assembleRelease
- 每次 push 都发布到 production 轨道
- 每个改动的 PR 都跑模拟器
- 复用拥有整个组织 owner 权限的 service account JSON
与其他技能的集成
Pipeline: github-actions;App: android-development;测试: android-unit-testing / android-instrumented-testing;iOS: github-actions-ios;上线: production-readiness。
完成标准
- PR 中执行 lint + unit
- 通过 secrets 用 upload key 签名 AAB
- 上传到非 production 轨道(或受保护的 production)
- versionCode 唯一且递增
- git 中没有 keystore