Flutter CI/CD 完整指南:从 Bitbucket Pipelines 到 Play Store 自动化部署

手动构建、签名和上传 Flutter 应用的过程既繁琐又容易出错 。你得找到正确的签名密钥,记住密码,运行构建命令,然后小心翼翼地将生成的 .aab.apk 文件上传到 Google Play Console。这个过程不仅耗时,而且严重拖慢了版本更新的速度。

持续集成与持续部署(CI/CD) 就是解决之道。通过建立一条自动化流水线,我们可以确保每一次代码推送到仓库后,都能自动完成分析、测试、构建,甚至部署。

本指南将带领你使用 Bitbucket PipelinesFastlane,为你的 Flutter 应用搭建一条完整的 CI/CD 流水线。我们将从基础的测试和签名应用包构建开始,逐步实现完全自动部署到 Google Play 商店的内部测试轨道。


准备工作

  • 一个已在 Bitbucket 仓库中的 Flutter 项目。
  • 一个 Android 签名密钥.jks 文件)及其凭证(密钥库密码、密钥别名、密钥密码)。
  • 你的 Bitbucket 仓库的管理权限

第一部分:奠定基础 --- 每次推送都进行构建和测试

首先,让我们创建一个能够在每次代码推送时,验证代码并构建已签名的 Android App Bundle 的流水线。

步骤 1:启用 Bitbucket Pipelines

这是最简单的一步:

  1. 在 Bitbucket 上导航到你的仓库
  2. 在左侧边栏,点击 仓库设置(Repository settings)
  3. 在"Pipelines"部分下,点击 设置(Settings)
  4. 切换开关以启用 Pipelines。Bitbucket 会提供一些模板,目前你可以先忽略。

步骤 2:创建 bitbucket-pipelines.yml 文件

在你的 Flutter 项目的根目录(与 pubspec.yaml 同级),创建一个名为 bitbucket-pipelines.yml 的新文件。这个文件是自动化流程的核心,包含流水线的所有指令。

步骤 3:定义 Docker 镜像和缓存

YAML 文件的第一部分是定义执行环境。我们将使用一个社区维护的Flutter Docker 镜像的特定版本(这里以 Flutter 3.32.7 为例)。同时,缓存也至关重要,它可以避免每次构建时都重新下载 Flutter SDK 和 pub 包,从而加快构建速度。

yaml 复制代码
image: ghcr.io/cirruslabs/flutter:3.32.7

definitions:
  caches:
    # Cache the Flutter SDK between builds
    flutter: /flutter
    # Cache the pub packages
    pub: $HOME/.pub-cache

clone:
  depth: 1 # Perform a shallow clone for faster checkout

步骤 4:创建第一个流水线(分析与测试)🧪

现在,我们来配置一个简单的流水线,让它在推送到任意分支时自动运行。这条流水线将负责拉取依赖项、分析代码并运行测试。

请将以下内容添加到你的 bitbucket-pipelines.yml 文件中:

yaml 复制代码
pipelines:
  default:
    - step:
        name: Analyze and Test
        caches:
          - pub
        script:
          # Get Flutter packages
          - flutter pub get
          # Run the linter/analyzer
          - flutter analyze
          # Run all widget tests (you can comment this out if you don't have tests)
          - flutter test

步骤 4:创建第一个流水线(分析与测试)🧪

现在,我们来配置一条简单流水线 ,让它在代码推送到任意分支时自动运行。这条流水线将负责获取依赖项、分析代码,并运行测试。

请将以下内容添加到你的 bitbucket-pipelines.yml 文件中:

yaml 复制代码
pipelines:
  default:
    - step:
        name: Analyze and Test
        caches:
          - pub
        script:
          # Get Flutter packages
          - flutter pub get
          # Run the linter/analyzer
          - flutter analyze
          # Run all widget tests (you can comment this out if you don't have tests)
          - flutter test

配置详解 ⚙️

让我们来分解一下这段配置的含义:

  • pipelines > default : 定义了一个流水线,它会在每一次提交(commit) 被推送时运行。
  • step : 一个流水线由一个或多个步骤组成,每个步骤都在一个全新的 Docker 容器中运行。
  • name: 一个描述性的名称,它将显示在 Bitbucket 的用户界面(UI)中。
  • caches : 指定此步骤应该使用我们在前面定义过的 pub 缓存
  • script : 需要按顺序执行的 Shell 命令列表

提交并推送 这个文件。你应该就能在仓库的 "Pipelines" (流水线)部分看到你的第一个流水线开始运行了。


步骤 5:处理 Android 构建所需的密钥信息 🔑

绝不应该将你的签名密钥或密码直接提交到仓库中。Bitbucket 提供了一种安全的方式来处理这些敏感信息,那就是**"仓库变量"(Repository variables)**。

5a. 编码你的 Keystore 文件和凭证

你的 .jks 文件是一个二进制文件。为了将其作为变量存储,我们必须使用 Base64 将其编码成文本格式。打开终端并运行相应的命令:

yaml 复制代码
# On macOS/Linux  
base64 -i my-upload-key.jks -o key.txt  
  
# On Windows (using PowerShell)  
[Convert]::ToBase64String([IO.File]::ReadAllBytes("my-upload-key.jks")) | Out-File -FilePath "key.txt"

运行上述命令会生成一个名为 key.txt 的文件,其中包含一个很长的字符串。请复制整个字符串。

现在,我们用同样的方法 来处理 key.properties 文件,以便编码访问 .jks 文件所需的凭证

yaml 复制代码
# On macOS/Linux  
base64 -i key.properties -o properties.txt  
  
# On Windows (using PowerShell)  
[Convert]::ToBase64String([IO.File]::ReadAllBytes("key.properties")) | Out-File -FilePath "properties.txt"

5b. 将变量添加到 Bitbucket 🔐

前往 仓库设置(Repository settings) -> 流水线(Pipelines) -> 仓库变量(Repository variables)

添加以下变量。至关重要 的一点是,请为每个变量都勾选"已保护"(Secured)框

typescript 复制代码
| Variable Name             | Value                                              |
| ------------------------- | -------------------------------------------------- |
| `ANDROID_KEYSTORE_BASE64` | Paste the entire base64 string from `key.txt`.     |
| `ANDROID_KEYPROPERTIES_BASE64` | Paste the entire base64 string from `properties.txt`.                   |

步骤 6:构建已签名的 Android 应用包(AAB)✅

现在,让我们创建一个新的流水线,让它在每次推送到 development 分支 时,自动构建一个已签名的 .aab 文件

请将以下代码块添加到你的 .yml 文件的 pipelines 键下:

bash 复制代码
# ... (image, definitions, and default pipeline from above) ...
pipelines:
  # ... (default pipeline here) ...
  branches:
    development:
      - step:
          name: Analyze and Build App Bundle
          size: 2x # Use a larger build container for performance
          caches:
            - pub
          script:
            - rm -f pubspec.lock
            - flutter pub get
            - flutter analyze
            - flutter test

            # Decode and write the keystore file from the repository variable
            - echo $ANDROID_KEYSTORE_BASE64 | base64 -d > android/app/keystore.jks

            # Create the key.properties file with the keystore credentials
            - echo $ANDROID_KEYPROPERTIES_BASE64 | base64 -d > android/key.properties

            # Build the app bundle
            - flutter build appbundle --obfuscate --split-debug-info=./debug_info -t lib/main_dev.dart --release
          artifacts:
            # Save the built app bundle so it can be downloaded
            - build/app/outputs/bundle/release/app-release.aab

关键新增内容解析 💡

  • branches > development : 这条流水线只会 在代码推送到 development 分支时运行。
  • size: 2x : 构建 Flutter 应用是资源密集型的。设置 2x 会分配双倍内存,这能防止构建错误并加快速度。
  • echo ... | base64 -d ... : 这是至关重要的命令 ,它反转了我们之前的步骤。它取出安全的变量,将其从 Base64 解码 ,并重新写入一个二进制的 .jks.properties 文件
  • flutter build appbundle ... : 我们使用标准的构建命令,带有混淆 (obfuscation)和一个特定的入口点(-t lib/main_dev.dart)。
  • artifacts : 这告诉 Bitbucket 保存 指定的文件(app-release.aab),你可以在流水线结果页面下载它。

第二部分:最后冲刺 --- 使用 Fastlane 自动化部署到 Play Store 🚀

构建应用固然很好,但真正的魔力在于自动化部署 。为此,我们将集成 Fastlane------一个专为自动化应用发布而设计的开源平台。

新工作流程概览

  1. 本地设置: 我们将先在本地设置 Fastlane,确保它可以正确地与 Google Play 商店通信。
  2. Google 凭证 : 我们将创建一个 Google Cloud 服务账号,Fastlane 将使用它进行身份验证。
  3. 安全变量 : 我们将对秘密的服务账号 JSON 密钥进行编码,并将其安全地存储在 Bitbucket 中。
  4. 流水线更新 : 我们将修改 .yml 文件,使其安装并运行 Fastlane,由 Fastlane 处理构建和部署工作。

步骤 1:获取 Google Play API 凭证 🔑

Fastlane 需要一个服务账号才能代表你执行操作。

创建服务账号

  1. Google Cloud Console 中,导航到 IAM 与管理(IAM & Admin) -> 服务账号(Service Accounts)
  2. 点击 + 创建服务账号(+ CREATE SERVICE ACCOUNT) ,给它命名(例如:bitbucket-ci-cd-deploys),然后点击 创建并继续(CREATE AND CONTINUE)
  3. 在"授予此服务账号对项目的访问权限"下,添加角色 "服务账号用户"(Service Account User) 。点击 继续(CONTINUE) ,然后 完成(DONE)

创建并下载 JSON 密钥

  1. 找到你刚创建的服务账号。点击旁边的三个点菜单 ,选择 管理密钥(Manage keys)
  2. 点击 添加密钥(ADD KEY) -> 创建新密钥(Create new key) 。选择 JSON 并点击 创建(CREATE)
  3. 一个 JSON 文件(例如:your-service-account-key.json)将被下载。这个文件就是你的密码,务必保持安全,不要提交到仓库中。

在 Play Console 中授予权限

  1. 前往 Google Play Console用户与权限(Users & Permissions) 页面,点击 邀请新用户(Invite new users)
  2. 粘贴服务账号的电子邮件地址 ,并授予所需的权限(例如:管理员(Admin) 或特定的 发布经理(Release Manager) 角色)。点击 邀请用户(Invite user)

步骤 2:在本地安装和配置 Fastlane 🛠️

我们将在你的 Flutter 项目的 android 目录中设置 Fastlane。

安装 Fastlane

请遵循 Fastlane 官方设置指南。强烈建议使用 Bundler

初始化 Fastlane

  1. 在终端中进入你的项目 android 目录cd android
  2. 运行 fastlane init
  3. 它会要求输入你的应用的包名秘密 JSON 文件 的路径(例如:./your-service-account-key.json)。

配置 fastlane/Appfile

确保其中的路径设置是正确的。

bash 复制代码
# fastlane/Appfile  
json_key_file("./your-service-account-key.json") # Path to your JSON key  
package_name("com.your.app.package")

4. 安装 flutter_version 插件 🛠️

为了能自动pubspec.yaml 文件中获取应用的版本名称(version name)版本代码(version code) ,请在 android 目录下运行此命令:

bash 复制代码
  bundle exec fastlane add_plugin flutter_version

5. 配置 fastlane/Fastfile 🛠️

这里就是你定义 "快车道"(lanes) 的地方。请用以下内容替换掉文件中的原有内容:

ruby 复制代码
# fastlane/Fastfile
default_platform(:android)

platform :android do
  desc "Builds and deploys to the Google Play internal testing track"
  lane :deploy_internal do
    # Go up to the root to run Flutter commands
    Dir.chdir("..") do
      sh("flutter", "build", "appbundle", "--obfuscate", "--split-debug-info=./debug_info", "-t", "lib/main_dev.dart", "--release")
    end
    
    version_info = flutter_version()
    version_name = version_info["version_name"] # e.g., "1.2.3"
    build_number = version_info["version_code"] # e.g., "45"

    # Upload to the Play Store
    upload_to_play_store(
      track: 'internal', # Deploy to the internal testing track
      aab: '../build/app/outputs/bundle/release/app-release.aab',
      version_name: "#{version_name}(#{build_number})"
    )
  end
end

6. 在本地进行测试(强烈推荐)✅

在你的终端(仍需位于 android 目录 中)运行命令:fastlane deploy_internal。如果这条命令成功运行,那么你就准备好进行自动化部署了。

更新 .gitignore 文件 🔒

确保 你的根目录下的 .gitignore 文件包含了那个秘密的 JSON 密钥文件:

bash 复制代码
/android/your-service-account-key.json  
/android/gemfile.lock

步骤 4:更新 Bitbucket Pipelines 以进行部署 🚀

最后一步,让我们把 Fastlane 集成到 bitbucket-pipelines.yml 文件中。

将 JSON 密钥添加为安全变量 🔒

像处理 Keystore 文件一样,你需要对 JSON 密钥文件进行编码:

vbnet 复制代码
 base64 -i your-service-account-key.json -o play-key.txt

将字符串从 play-key.txt 文件中复制出来。

前往 仓库设置(Repository settings) -> 仓库变量(Repository variables) ,添加一个新的受保护变量 ,命名为 GPLAY_SERVICE_ACCOUNT_KEY_BASE64,并将复制的字符串粘贴为它的值。

修改 bitbucket-pipelines.yml 文件 ⚙️

用这个新版本 的流水线替换掉你原有的 development 分支流水线。它会简化很多 ,因为 Fastlane 替我们处理了大部分逻辑。

yaml 复制代码
branches:
  development:
    - step:
        name: Build and Deploy to Internal Testing
        size: 2x
        caches:
          - pub
        script:
          # Basic setup and analysis
          - rm -f pubspec.lock
          - flutter pub get
          - flutter analyze
          
          # Restore Android Keystore for the build
          - echo $ANDROID_KEYSTORE_BASE64 | base64 -d > android/app/keystore.jks
          
          # Create the key.properties file with the keystore credentials
          - echo $ANDROID_KEYPROPERTIES_BASE64 | base64 -d > android/key.properties

          # Restore Google Play API key for Fastlane
          - echo $GPLAY_SERVICE_ACCOUNT_KEY_BASE64 | base64 -d > android/your-service-account-key.json

          # --- Deployment via Fastlane ---
          - cd android
          - bundle install
          - bundle exec fastlane deploy_internal
        artifacts:
          # Save the built artifact just in case
          - build/app/outputs/bundle/release/app-release.aab

结论 🎉

恭喜! 你现在拥有了一条强大且完全自动化的 CI/CD 流水线。

今后,每一次推送到你的 development 分支 的代码,都将无需任何手动干预 ,自动完成分析、构建、签名,并部署到 Google Play 商店的内部测试人员手中。

这套设置不仅为你节省了无数时间,还确保了发布流程的一致性、可靠性和安全性 ,让你能够专注于你最擅长的事情:构建出色的应用!

相关推荐
JarvanMo2 小时前
Flutter3.38 带来了什么
前端
倚栏听风雨2 小时前
React中useCallback
前端
不说别的就是很菜2 小时前
【前端面试】前端工程化篇
前端·面试·职场和发展
亿元程序员2 小时前
微信小游戏包体限制4M,一个字体就11.24M,怎么玩?
前端
涔溪2 小时前
vue中预览pdf文件
前端·vue.js·pdf
天若有情6732 小时前
从零实现轻量级C++ Web框架:SimpleHttpServer入门指南
开发语言·前端·c++·后端·mvc·web应用
摇滚侠2 小时前
css,控制超出部分隐藏,显示... css,控制超出部分不隐藏,换行
前端·css
IT_陈寒2 小时前
Python 3.12 新特性实战:10个让你代码更优雅的隐藏技巧
前端·人工智能·后端
一 乐3 小时前
海产品销售系统|海鲜商城购物|基于SprinBoot+vue的海鲜商城系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·后端