@freeCodeCamp: 如果构建、签名、环境配置和商店发布仍然手动操作,Flutter 应用很难安全发布…
摘要
本教程教你如何使用 GitHub Actions 构建可用于生产的 Flutter CI/CD 管道,包括质量门禁、Firebase 和 TestFlight 分发,以及 Sentry 符号上传。
查看缓存全文
缓存时间: 2026/07/28 14:27
一个Flutter应用在构建、签名、环境配置和应用商店发布仍手动进行时,很难安全地发布。在本教程中,@devseyi 将帮助你使用 GitHub Actions 构建一个生产就绪的 Flutter CI/CD 流水线。你还将学习如何使用 Firebase 和 TestFlight 分发测试构建,上传 Sentry 符号,以及自动化部署。https://freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/… — # 如何使用 GitHub Actions 构建生产就绪的 Flutter CI/CD 流水线:质量门、环境和应用商店部署 来源:https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/ 移动应用开发多年来一直在演变。我们使用的流程、结构、语法以及所构建应用的质量和灵活性都发生了变化。其中一项主要改进是精心自动化的 CI/CD 流水线流程,它为我们提供了无缝的自动化、持续集成和持续部署。在本文中,我将分解如何为你的 Flutter 应用使用 GitHub Actions 自动化和构建一个生产就绪的 CI/CD 流水线。请注意,还有其他方法可以做到这一点,例如使用 Codemagic(专为 Flutter 应用构建——我将在后续教程中介绍),但在本文中,我们将重点介绍 GitHub Actions。 ## 目录 1. 典型工作流 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-the-typical-workflow) 2. 前提条件 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-prerequisites) 3. 流水线架构 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-pipeline-architecture) 4. 编写工作流 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-writing-the-workflows) - 辅助脚本 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-the-helper-scripts) - generate_config.sh (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-script-1-generateconfigsh) - quality_gate.sh (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-script-2-qualitygatesh) - upload_symbols.sh (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-script-3-uploadsymbolssh-sentry) - PR 质量门 (pr_checks.yml) (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-workflow-1-prchecksyml) - Android CI/CD 流水线 (android.yml) (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-workflow-2-androidyml) - iOS CI/CD 流水线 (ios.yml) (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-workflow-3-iosyml) 5. 秘密与配置参考 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-secrets-and-configuration-reference) 6. 端到端流程 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-end-to-end-flow) 7. 结论 (https://www.freecodecamp.org/news/how-to-build-a-production-ready-flutter-ci-cd-pipeline-with-github-actions-quality-gates-environments-and-store-deployment/#heading-conclusion) ## 典型工作流 首先,让我们定义部署生产就绪 Flutter 应用的常见方法。开发团队在本地工作,推送到仓库进行合并或审查,然后运行 flutter build apk 或 flutter build appbundle 来生成 apk 文件。然后手动与 QA 团队共享,或部署到 Firebase App Distribution 进行测试。如果是生产版本,则将应用包提交到 Google Play 商店进行审查,然后部署。这个过程通常完全是手动的,没有自动化检查、验证,也没有对质量、速度和流畅性的控制。手动发布 Flutter 应用开始相对简单,但很快可能会悄然变成一项负担。你运行 flutter build,切换配置,签名构建,上传到某个地方,并希望没有混淆 staging 密钥和生产密钥。随着团队发展以及发布更新越来越频繁,这些手动步骤就会成为真正的风险。跳过的质量检查、遗失的密钥库,或部署到生产环境的错误基础 URL,都可能导致数小时的调试,甚至更糟——影响到你的用户。完全自动化这个过程需要一些高级配置和预定义的脚本。它完全掌控了从开发者向公共或基础分支(例如 develop 分支)提出 PR 那一刻起的部署过程。这个自动化过程负责完成所有需要完成的任务——前提是它已被预定义、正确编写脚本,并与团队的使用场景相匹配。 ### 我们将在此完成的工作: 在本教程中,我们将使用 GitHub Actions 为 Flutter 应用构建一个生产级 CI/CD 流水线。该流水线自动化了整个生命周期:PR 质量检查、环境特定配置注入、Android 和 iOS 构建、面向测试人员的 Firebase App Distribution、Sentry 符号上传,以及最终部署到 Play Store 和 App Store。最终,每一次发布——从开发者打开 PR 到最终构建到达用户手中——都将完全自动化,无需任何人接触终端。 ## 前提条件 在开始之前,你应该具备: 1. 一个具有可用的 Android 和 iOS 构建的 Flutter 应用 2. 对 GitHub Actions 有基本了解 (https://www.freecodecamp.org/news/automate-cicd-with-github-actions-streamline-workflow/)(工作流和作业) 3. 一个已启用 App Distribution 的 Firebase 项目 4. 一个用于错误追踪的 Sentry 项目 5. 一个已在 Google Play Console 中创建的应用 6. 一个具有 App Store Connect 访问权限的 Apple Developer 账户 7. 已为你的 iOS 项目配置 Fastlane 8. 基本的 Bash 知识(我会解释重要部分) ## 流水线架构 在本指南中,我们将构建一个具有非常精确指令和用例的 CI/CD 流水线。这些用例决定了你构建流水线的方式。在本教程中,我们将使用以下用例:我希望基于以下标准自动化开发团队的工作流: 1. 当团队中的开发者向公共工作分支(大多数情况下为 develop)提出 PR 时,触发一个工作流来对代码进行质量检查。它只允许在所有检查(如测试覆盖率、质量检查和静态分析)通过时才进行合并。 2. 从 develop 分支移动到 staging 分支的代码通过另一个工作流,该工作流注入 staging 配置/密钥,执行所有必要的检查,并将应用分发进行测试,通过 Firebase App Distribution(Android)和 Testflight(iOS)。 3. 从 staging 分支移动到 production 分支的代码通过生产级工作流,涉及 apk 安全签名、生产配置注入、运行测试以确保没有破坏、用于监控的 Sentry 分析,以及提交到 App Store Connect 和 Google Play Console。 这些是我们预定义的条件,有助于构建我们的工作流。 ## 编写工作流 我们将把这个流水线拆分为三个 GitHub Actions 工作流。我们还将更进一步,创建三个辅助的 .sh 脚本,以便工作流更清晰、更易于维护。 在你的项目根目录中,创建两个文件夹: 1. .github/ 2. scripts。** .github/** 文件夹将包含我们为每个用例创建的工作流,而 scripts/ 文件夹将包含辅助脚本,我们可以轻松地在 CLI 中或直接在工作流中调用它们。 之后,我们将创建三个工作流 .yaml 文件: 1. pr_checks.yaml 2. android.yaml 3. ios.yaml 同时在 scripts 文件夹中,创建三个 .sh 文件: 1. generate_config.sh 2. quality_checks.sh 3. upload_symbols.sh .github/ workflows/ pr_checks.yml android.yml ios.yml scripts/ generate_config.sh quality_checks.sh upload_symbols.sh 这种工作流架构确保推送到 develop 会自动生成测试构建。同样,合并到 production 会直接发送到商店,无需手动命令或配置更改。脚本故意放在 YAML 之外。这样可以让你在本地运行相同的逻辑。 ### 辅助脚本 脚本构成了流水线的骨干。每个脚本都有单一的职责,并在工作流中复用。我们不会把逻辑塞进 YAML,而是将其移到可重用脚本中。这保持了工作流的整洁,并让你可以在本地运行相同的逻辑。现在让我们逐一了解它们。 ### 脚本 #1:generate_config.sh 安全地注入秘密是移动应用 CI/CD 中最难的问题之一。策略如下: - 提交一个带有占位符的 Dart 模板文件 - 在构建时使用 GitHub Actions 中的秘密替换占位符 - 绝不提交真实凭据 #!/usr/bin/env bash set -euo pipefail ENV_NAME=${1:-} BASE_URL=${2:-} ENCRYPTION_KEY=${3:-} TEMPLATE="lib/core/env/env_ci.dart" OUT="lib/core/env/env_ci.g.dart" if [ -z "\(ENV_NAME" ] || [ -z "\)BASE_URL" ] || [ -z "$ENCRYPTION_KEY" ]; then echo "Usage: $0 " exit 2 fi sed -e "s|<>|$BASE_URL|g" \ -e "s|<>|$ENCRYPTION_KEY|g" \ -e "s|<>|$ENV_NAME|g" \ "\(TEMPLATE" > "\)OUT" echo "Generated config for $ENV_NAME" 该脚本负责在构建时将环境特定配置注入 Flutter 应用,而无需将秘密提交到源代码管理。让我们仔细分析一下。 #### 1. Shebang:选择 Shell #!/usr/bin/env bash 这行告诉系统使用Bash来执行脚本,无论 Bash 安装在机器的哪个位置。使用 /usr/bin/env bash 而不是 /bin/bash 使得脚本在本地机器、GitHub Actions 运行器和 Docker 容器之间更具可移植性。 #### 2. 快速失败,发出响亮信号 set -euo pipefail 这是脚本中最重要的行之一。它启用了三种严格的 Bash 模式: - -e:如果任何命令失败,立即退出 - -u:如果使用了未定义的变量,退出 - -o pipefail:如果管道中的任何命令失败,则失败,而不仅仅是最后一个命令 这在 CI 中很重要,因为静默失败是危险的,部分配置生成可能破坏生产构建,并且 CI 应该在出现问题时立即停止。这行确保没有损坏的配置会进入构建。 #### 3. 读取输入参数 ENV_NAME=${1:-} BASE_URL=${2:-} ENCRYPTION_KEY=${3:-} 这些行读取传递给脚本的位置参数: - $1:环境名称(dev、staging、production) - $2:API 基础 URL - $3:加密密钥或 API 密钥 $\{1:-\} 语法的意思是:“如果参数缺失,则默认为空字符串而不是崩溃。” 这与 set -u 配合使用,我们可以显式控制失败,而不是让 Bash 意外爆炸。 #### 4. 定义输入和输出文件 TEMPLATE="lib/core/env/env_ci.dart" OUT="lib/core/env/env_ci.g.dart" 这里我们定义了两个文件: - 模板文件(env_ci.dart) - 包含类似 <> 的占位符值 - 可以安全地提交到 Git - 生成文件(env_ci.g.dart) - 包含真实的環境值 - 必须被 Git 忽略(.gitignore) 这种方法的核心是两个具有截然不同职责的 Dart 文件。它们可能看起来相似,但在系统中扮演着完全不同的角色。 #### env.ci.dart: // lib/core/env/env_ci.dart class EnvConfig { static const String baseUrl = '<>'; static const String encryptionKey = '<>'; static const String environment = '<>'; } 这个文件是安全的、静态的,并且是受版本控制的。它包含占位符,而不是真实值。它的一些关键特性包括: - 不包含真实的秘密 - 使用明显的占位符(<> 等) - 可以安全地提交到 Git - 像普通源代码一样被审查 - 作为所需配置字段的单一真实来源 将此文件视为一个契约:“这些是应用在运行时期望的配置值。” #### env.ci.g.dart: 该文件在构建时由 generate_config.sh 生成。替换后,它看起来像这样: // lib/core/env/env_ci.g.dart // 生成文件 — 请勿提交 class EnvConfig { static const String baseUrl = 'https://staging.api.example.com'; static const String encryptionKey = 'sk_live_xxxxx'; static const String environment = 'staging'; } 关键特性: - 包含真实的環境值 - 在 CI 中动态生成 - 针对不同环境(dev / staging / production)而不同 - 必须永不提交到源代码管理 这个文件只存在于开发者的机器上(如果在本地生成),在 CI 运行器中构建期间存在,一旦作业完成,它就消失了。 #### .gitignore: 为了保证生成的文件不会泄露,必须忽略它: #### 为什么这种分离至关重要 这种设计同时解决了好几个难题。 安全性: - 秘密仅存在于 GitHub Actions 的秘密中 - 它们永远不会出现在仓库中 - 它们永远不会出现在 PR 中 - 它们永远不会出现在 Git 历史中 环境隔离: 每个环境获得自己的生成配置: - develop:开发 API - staging:预发布 API - production:生产 API 相同的代码库表现不同而不需要在 Dart 中添加分支逻辑。 确定性构建: 每个构建是完全可重现的、完全自动化的,并明确其目标环境。没有“它在本地能行”的情况。 #### 5. 验证必需参数 if [ -z "\(ENV_NAME" ] || [ -z "\)BASE_URL" ] || [ -z "$ENCRYPTION_KEY" ]; then echo "Usage: $0 " exit 2 fi 这个块强制执行正确的使用方式。 - -z 检查变量是否为空 - 如果任何必需的参数缺失: - 打印一条有用的使用信息 - 脚本以非零状态码退出 - 0:成功 - 1+:失败 - 2 常规表示用法错误 在 CI 中,这会立即失败作业并阻止无效构建。 #### 6. 注入環境值 sed -e "s|<>|$BASE_URL|g" \ -e "s|<>|$ENCRYPTION_KEY|g" \ -e "s|<>|$ENV_NAME|g" \ "\(TEMPLATE" > "\)OUT" 这是脚本的核心。这里发生了什么: 1. sed 执行流编辑:它读取文本,转换它,并输出结果 2. 每个 -e 标志定义一个替换规则: - 用实际的 API URL 替换 <> - 用真实的密钥替换 <> - 用環境标签替换 <> 3. 转换后的输出被写入 env_ci.g.dart 整个操作在构建时发生: - 没有提交秘密 - 没有秘密
相似文章
@freeCodeCamp:内部开发者平台能帮助团队加快交付速度,无需手动管理基础设施。在本指南中,Ayobami…
一份关于使用Backstage、ArgoCD和Crossplane构建内部开发者平台的综合指南,让团队能够自助获取基础设施和部署服务,无需手动填写工单流程。
flutter/flutter
Flutter 是 Google 的开源 SDK,用于从单一代码库构建美观、快速的跨平台应用。这是 Flutter 的官方 GitHub 仓库。
@freeCodeCamp: 很多RAG教程在本地运行没问题,但一旦尝试部署就会出问题。在这本手册中,@dannwaneri 教你…
这本手册教开发者如何构建一个生产级RAG系统,使用Cloudflare Workers、Vectorize和Workers AI,专注于成本效益和可靠性。
@jholtdigital:最近有位朋友鼓励我,如果想了解某件事物对我的用例效果如何,就应该试用一个月……
一位用户分享了使用 FactoryAI 将设计系统从 HTML/CSS 转换为带有 E2E 测试的 Flutter 组件的体验。该工具使用编排器、工作者和验证器,结合多种 AI 模型来规划和执行长达 79 小时的长期任务,总共生成了超过 229 个代理。
使用Go开发移动应用
一位开发者分享了使用Go Mobile为Flutter应用构建后端的经验,详细介绍了通过protobuf和平台通道进行通信的方式。