开篇:为什么 CI/CD 对 Flutter 至关重要
移动端应用的分发流程远比 Web 复杂:iOS 需要证书、Provisioning Profile、App Store Connect 审核;Android 需要密钥库、Play Store 签名(bundle signing)。手动执行这些步骤不仅耗时且容易出错,尤其在团队协作中,“我本地能跑但 CI 挂了"是最常见也最头痛的问题。
建立一条完整的 CI/CD 流水线,让每次代码提交自动触发代码检查、测试、构建和分发,是 Flutter 项目走向专业化的必经之路。
一、方案选型
| 方案 | 托管 | 价格 | 特点 |
|---|---|---|---|
| GitHub Actions | GitHub | 免费额度/按量 | 与代码仓库深度集成,社区生态丰富 |
| Codemagic | 独立 SaaS | 免费 500min/月 | Flutter/Dart 原生优化,M1 Mac 构建 |
| Bitrise | 独立 SaaS | 免费额度 | 移动优先,工作流可视化编辑 |
| CircleCI | 独立 SaaS | 按量 | 高度可配置,Docker 支持好 |
一句话总结:大多数团队从 GitHub Actions 起步(零额外成本),对构建速度要求高的团队可升级到 Codemagic 的 M1 构建.
二、GitHub Actions 工作流
# .github/workflows/flutter_ci.yml
name: Flutter CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# 阶段 1: 代码分析与测试
analyze-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
channel: 'stable'
cache: true
- name: Get dependencies
run: flutter pub get
- name: Generate code
run: dart run build_runner build --delete-conflicting-outputs
- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .
- name: Analyze project source
run: flutter analyze --fatal-infos
- name: Run tests with coverage
run: flutter test --coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: coverage/lcov.info
# 阶段 2: Android 构建
build-android:
needs: analyze-and-test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
channel: 'stable'
cache: true
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Build APK
run: flutter build apk --release
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
- name: Build App Bundle
run: flutter build appbundle --release
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: android-builds
path: |
build/app/outputs/flutter-apk/*
build/app/outputs/bundle/release/*
# 阶段 3: iOS 构建
build-ios:
needs: analyze-and-test
runs-on: macos-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
channel: 'stable'
cache: true
- name: Install dependencies
run: flutter pub get
- name: Setup certificates
env:
P12_CERTIFICATE_BASE64: ${{ secrets.P12_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
run: |
echo "$P12_CERTIFICATE_BASE64" | base64 --decode > certificate.p12
security create-keychain -p "password" build.keychain
security import certificate.p12 -t agg -k build.keychain -P "$P12_PASSWORD" -A
- name: Build iOS
run: flutter build ios --release --no-codesign
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ios-build
path: build/ios/iphoneos/*.app
# 阶段 4: Web 构建
build-web:
needs: analyze-and-test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
- run: flutter pub get
- run: flutter build web --release
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
一句话总结:GitHub Actions 通过 YAML 定义工作流,将代码检查、测试、多平台构建串联为自动化流水线,是 Flutter 项目 CI/CD 的入门首选。
三、Fastlane 自动化分发
# android/fastlane/Fastfile
default_platform(:android)
platform :android do
desc "Deploy to Play Store Internal"
lane :internal do
flutter_command(command: "build appbundle --release")
upload_to_play_store(
track: 'internal',
aab: '../build/app/outputs/bundle/release/app-release.aab',
json_key_data: ENV['PLAY_STORE_JSON_KEY'],
)
end
desc "Deploy to Firebase App Distribution"
lane :beta do
flutter_command(command: "build apk --release")
firebase_app_distribution(
app: ENV['FIREBASE_APP_ID'],
groups: "testers",
apk_path: "../build/app/outputs/flutter-apk/app-release.apk",
service_credentials_file: "firebase-service-account.json",
)
end
end
一句话总结:Fastlane 封装了各大平台的分发 API,将原本需要 Web 控制台操作的多步流程简化为一条命令。
FAQ
Q1: 代码签名证书如何安全存储?
- GitHub Secrets:适合大多数场景
- 1Password/HashiCorp Vault:企业级密钥管理
- 切勿将密钥提交到版本控制
Q2: iOS 构建为什么比 Android 慢?
iOS 编译需要在 macOS 上运行 Xcode,GitHub Actions 的 macOS runner 比 Linux runner 慢且贵。Codemagic 提供专用 M1 构建机,速度提升 2-3 倍。
Q3: Web 构建产物如何部署?
Flutter Web 输出为静态文件,可部署到任何静态托管:Vercel、Netlify、Firebase Hosting、GitHub Pages、AWS S3 + CloudFront。
相关阅读
- https://plumephp.com/flutter-testing/ — 测试策略与自动化
- https://plumephp.com/flutter-web-desktop/ — Web 与桌面端构建配置
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。