跳转至正文
CI/CD

使用 GitLab 自动进行 Capacitor Android build

5 分钟上手:使用 fastlane 和 GitLab 为你的 Ionic Android 应用搭建 CI/CD pipeline

使用 GitLab 自动进行 Capacitor Android build

使用 GitLab CI 实现 Android 自动化构建

为 Capacitor 应用配置 CI/CD 可能既复杂又耗时。你需要了解这些:

前提条件

在开始之前,你需要完成以下设置:

  • 具有管理员权限的 GitLab 账号
  • 已在 Google Play Store 发布并完成正确签名的 App
  • Android 签名密钥及 keystore 文件
  • 已启用 Play Store API 的 Google Cloud Console 项目
  • 具有相应权限的服务账号 (Service account)
  • 了解 GitLab CI/CD 工作流
  • 熟悉 Fastlane 配置
  • 用于维护和调试 pipeline 的时间

Capgo 通过 Capgo 进行 CI/CD 构建

省去 Fastlane、Gradle runner、keystore 和上传脚本的维护。 Capgo 构建 从你现有的 CI/CD 流水线运行已签名的原生 Android 构建:

  • 适配你的流水线: 在 Web 构建完成后,通过 GitLab CI、GitHub Actions、Jenkins 或本地脚本触发 Capgo Native Build npx cap sync.
  • 通过 CI secrets 签名:将 Android keystores、key aliases、密码以及 Play Console 服务账号 JSON 保存在你自己的 CI secrets 中。
  • 无需维护原生 runner:Capgo Build 提供持续维护的 Android 构建环境,因此你无需管理 SDK 镜像、Gradle 缓存问题或 Fastlane lanes。
  • 产物与提交:下载已签名的产物用于 QA,或通过 Capgo CLI 提交发布构建。

定价

  • Capgo 套餐 $12/月起
  • 包含 OTA 更新和每月约 15 次 Native Build
  • 额外的构建分钟数通过 credits 按分钟计费

在 CI/CD 中配置 Capgo Build

手动配置指南

你需要做的是:

本文的操作步骤

  1. 复制 Fastlane 文件
  2. 在 GitLab 加密变量中存储密钥
  3. 创建并存储 Google Play 服务账号密钥
  4. 存储您的 Android 签名密钥
  5. 配置 GitLab workflow .yml 文件

1. 复制 Fastlane 文件

Fastlane 是一个 Ruby 库,用于自动化常见的移动开发任务。使用 Fastlane,你可以配置自定义的 “lanes”,这些 lanes 会打包一系列 “actions”,用来执行你通常会在 Android Studio 中完成的任务。Fastlane 能做很多事,但本教程只会用到少数几个核心 actions。

在项目根目录创建 Fastlane 文件夹并复制以下文件: Fastlane

default_platform(:android)

KEYSTORE_KEY_ALIAS = ENV["KEYSTORE_KEY_ALIAS"]
KEYSTORE_KEY_PASSWORD = ENV["KEYSTORE_KEY_PASSWORD"]
KEYSTORE_STORE_PASSWORD = ENV["KEYSTORE_STORE_PASSWORD"]

platform :android do
    desc "Deploy a beta version to the Google Play"
    private_lane :verify_changelog_exists do |version_code: |
      changelog_path = "android/metadata/en-US/changelogs/#{version_code}.txt"
      UI.user_error!("Missing changelog file at #{changelog_path}") unless File.exist?(changelog_path)
      UI.message("Changelog exists for version code #{version_code}")
    end

    private_lane :verify_upload_to_staging do |version_name: |
      UI.message "Skipping staging verification step"
    end
    lane :beta do
				keystore_path = "#{Dir.tmpdir}/build_keystore.keystore"
				File.write(keystore_path, Base64.decode64(ENV['ANDROID_KEYSTORE_FILE']))
				json_key_data = Base64.decode64(ENV['PLAY_CONFIG_JSON'])
				previous_build_number = google_play_track_version_codes(
					package_name: ENV['DEVELOPER_PACKAGE_NAME'],
					track: "internal",
					json_key_data: json_key_data,
				)[0]

				current_build_number = previous_build_number + 1
				sh("export NEW_BUILD_NUMBER=#{current_build_number}")
        gradle(
          task: "clean bundleRelease",
          project_dir: 'android/',
          print_command: false,
          properties: {
            "android.injected.signing.store.file" => "#{keystore_path}",
            "android.injected.signing.store.password" => "#{KEYSTORE_STORE_PASSWORD}",
            "android.injected.signing.key.alias" => "#{KEYSTORE_KEY_ALIAS}",
            "android.injected.signing.key.password" => "#{KEYSTORE_KEY_PASSWORD}",
						'versionCode' => current_build_number
          })
        upload_to_play_store(
					package_name: ENV['DEVELOPER_PACKAGE_NAME'],
					json_key_data: json_key_data,
          track: 'internal',
          release_status: 'completed',
          skip_upload_metadata: true,
          skip_upload_changelogs: true,
          skip_upload_images: true,
          skip_upload_screenshots: true,
        )
    end
    lane :build do
      gradle(
        task: "clean bundleRelease",
        project_dir: 'android/',
        print_command: false,
        properties: {
          "android.injected.signing.store.file" => "#{keystore_path}",
          "android.injected.signing.store.password" => "#{KEYSTORE_STORE_PASSWORD}",
          "android.injected.signing.key.alias" => "#{KEYSTORE_KEY_ALIAS}",
          "android.injected.signing.key.password" => "#{KEYSTORE_KEY_PASSWORD}",
        })
    end
    lane :prod_release do
      build_gradle = File.read("../android/app/build.gradle")

      verify_changelog_exists(version_code: build_gradle.match(/versionCode (\d+)/)[1])
      verify_upload_to_staging(version_name: build_gradle.match(/versionName '([\d\.]+)'/)[1])

      supply(
        track_promote_to: 'beta',
        skip_upload_apk: true,
        skip_upload_aab: true,
        skip_upload_metadata: false,
        skip_upload_changelogs: false,
        skip_upload_images: false,
        skip_upload_screenshots: false
      )
    end
end

在 GitLab CI/CD Variables 中存储密钥

GitLab 提供了一种存储加密 CI/CD 变量的方式,类似于 GitHub 的 repository secrets,用于安全地存储敏感信息。

  1. 前往 GitLab 项目的 Settings。
  2. 导航至 CI/CD > Variables
  3. 添加以下变量:
  • ANDROID_KEYSTORE_FILE:用于对 Android build 进行签名的 base64 编码 .jks 或 .keystore 文件。这可以是与你的 upload key 关联的 keystore 文件(如果使用 Play App Signing),或者是你的 app signing key。
  • KEYSTORE_KEY_PASSWORD:与 keystore 文件关联的密码
  • KEYSTORE_KEY_ALIAS:keystore 别名
  • KEYSTORE_STORE_PASSWORD:私钥密码
  • DEVELOPER_PACKAGE_NAME:你的 Android App ID,例如 com.example.app
  • PLAY_CONFIG_JSON:Base64 编码的服务账号密钥 JSON。

创建 Google Play 服务账号密钥

要生成 PLAY_CONFIG_JSON 密钥,请按照以下步骤操作:

  1. 前往 Google Cloud Console
  2. 新建项目或选择现有项目
  3. 启用 Google Play Android Developer API
  4. 创建服务账号:
    • 前往 “IAM & Admin” > “Service Accounts”
    • 点击 “Create Service Account”
    • 填写名称和描述
    • 点击“创建并继续”
    • 跳过角色分配,点击“完成”
  5. 生成 JSON 密钥:
    • 在列表中找到您的服务账号
    • 点击三点菜单 > “管理密钥”
    • 点击“添加密钥” > “创建新密钥”
    • 选择 JSON 格式
    • 点击“创建”
  6. 在 Play Console 中授予服务账号访问应用的权限:
    • 前往 Play Console
    • 前往“用户和权限”
    • 点击“Invite new users”
    • 输入服务账号邮箱(以 @*.iam.gserviceaccount.com 结尾)
    • 授予“Release to production”权限
    • 点击“Invite user”
  7. 将 JSON 密钥转换为 base64:
    base64 -i path/to/your/service-account-key.json | pbcopy
  8. 将 base64 编码字符串添加为 PLAY_CONFIG_JSON GitLab 中的变量

配置您的 GitLab CI/CD Pipeline

在项目根目录创建 .gitlab-ci.yml 文件来定义您的 CI/CD pipeline。以下是 pipeline 结构的示例:


image: mingc/android-build-box:latest

stages:
  - build
  - upload_to_capgo
  - build_and_upload_android

build:
  stage: build
  tags:
    - saas-linux-xlarge-amd64
  cache:
    - key:
        files:
          - bun.lockb
      paths:
        - .node_modules/
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - node_modules/
      - dist/
  only:
    - master

upload_to_capgo:
  stage: upload_to_capgo
  tags:
    - saas-linux-xlarge-amd64
  script:
    - npx @capgo/cli@latest bundle upload -a $CAPGO_TOKEN -c dev
  dependencies:
    - build
  when: manual
  only:
    - master

build_and_upload_android:
  tags:
    - saas-linux-xlarge-amd64
  stage:    build_and_upload_android
  cache:
    - key:
        files:
          - android/gradle/wrapper/gradle-wrapper.properties
      paths:
        - ~/.gradle/caches/
  script:
    - npx cap sync android
    - npx cap copy android
    - bundle exec fastlane android beta # We do create a tag for the build to trigger XCode cloud builds
  dependencies:
    - build
  when: manual
  only:
    - master

触发 Pipeline

每当您向 GitLab 仓库推送新 tag 时,GitLab CI/CD 会自动触发定义的 pipeline,并使用 Fastlane 构建并部署您的 Android 应用。

请务必根据您的项目结构和需求调整路径与依赖项。此配置将帮助您在 GitLab CI/CD 上实现 Android 应用的自动化部署。

总结

通过使用 mingc/android-build-box Docker 镜像配置 GitLab CI/CD,你可以实现 Android 应用构建流程的自动化,从而提升开发工作流的效率与可靠性。这种自动化能让你从繁琐的任务中解脱出来,专注于应用开发的核心环节,最终助力你更高效地交付高质量 Android 应用。

延续上一篇:使用 GitLab 实现 Capacitor Android 自动化构建

如果你正在使用 使用 GitLab 自动进行 Capacitor Android build 规划 CI/CD 自动化,并将其与 Capgo CI/CD 用于 Capgo CI/CD 中的产品工作流, Capgo Native Build 用于 Capgo Native Builds 中的产品工作流, Capgo 集成 用于 Capgo 集成中的产品工作流, CI/CD 集成 了解 CI/CD 集成的实现细节,以及 GitHub Actions 集成 有关 GitHub Actions 集成的实现细节。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。