Logofpack

CI recipes

GitHub Actions workflows for every platform, caching, secrets and machine-readable results.

CI 示例

各平台的 GitHub Actions 工作流、缓存、密钥与机器可读结果。

fpack is built for CI: no prompts, stable exit codes, JSON output, redacted logs. The recipes below use GitHub Actions; the commands are the same anywhere.

Principles#

  • Pin the version so CI is reproducible: dart pub global activate fpack 1.1.16.
  • Build each platform on its own OS. iOS and macOS on macos-*, Windows on windows-*, Linux on ubuntu-*; Android and web run anywhere (why).
  • Secrets through environment variables. Never in fpack.yaml (Secrets and variables).
  • Upload dist/. It contains the artifacts and SHA256SUMS.
  • Use --json and exit codes to decide what happens next (Exit codes and JSON).

Without a TTY, spinners and colors are turned off and a heartbeat line is printed every 60 seconds so CI does not time out on silence.

Android#

jobs:
  android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: dart pub global activate fpack 1.1.16 && echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
      - run: fpack build apk aab --split-per-abi=both
        env:
          FPACK_ANDROID_KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
          FPACK_ANDROID_KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
          FPACK_ANDROID_KEY_ALIAS: upload
      - uses: actions/upload-artifact@v7
        with: { name: android, path: dist/ }

Create the secret with base64 -i upload.jks | pbcopy (Linux: base64 -w0 upload.jks). Set FPACK_ANDROID_KEY_PASSWORD too if it differs from the keystore password. fpack writes the keystore to build/fpack/secrets/ with mode 0600 and deletes it after the build. Details: Android.

iOS and macOS#

  apple:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: dart pub global activate fpack 1.1.16 && echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
      - run: fpack build ipa dmg --json > result.json

Signed and notarized macOS builds need certificates in a temporary keychain and notary credentials: macOS: export the certificates for CI has the complete import step with an App Store Connect API key. Use --notarize-no-wait plus a later fpack notarize finish if you prefer not to hold a runner while Apple processes the upload.

Windows#

  windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: dart pub global activate fpack 1.1.16
      - run: fpack build windows exe

Inno Setup is preinstalled on GitHub's Windows runners; for code signing, base64 the .pfx into a secret and decode it on the runner (Windows).

Linux and web#

  linux:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: sudo apt-get install -y ninja-build libgtk-3-dev rpm
      - run: dart pub global activate fpack 1.1.16 && echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
      - run: fpack build linux deb rpm web

For snaps on ubuntu-24.04, set linux.snap.build_mode: destructive; use ubuntu-24.04-arm for an arm64 snap (Linux).

Tips#

  • Cache the core: the native core (about 4 MB) is downloaded once per version into ~/.cache/fpack (Linux), ~/Library/Caches/fpack (macOS) or %LOCALAPPDATA%\fpack (Windows). Cache that folder to skip the download.
  • Machine-readable results: fpack build … --json > result.json writes every artifact with path, size, SHA-256 and notarization state; human output goes to stderr.
  • Fail fast: exit code 3 means a prerequisite is missing; nothing was built.
  • A version per run: pass --build-number "$GITHUB_RUN_NUMBER" so reruns never collide with existing artifacts (versions).
  • Preview first: fpack build --all --dry-run in a pull request shows what a release would do.

fpack 为 CI 而生:不提问、退出码稳定、有 JSON 输出、日志已脱敏。下面的示例用 GitHub Actions,命令在任何 CI 中都一样。

原则#

  • 固定版本,保证 CI 可复现:dart pub global activate fpack 1.1.16。
  • 每个平台在自己的系统上构建。 iOS 和 macOS 用 macos-*,Windows 用 windows-*,Linux 用 ubuntu-*;Android 和 Web 在哪里都行(为什么)。
  • 密钥通过环境变量传入。 永远不要写进 fpack.yaml(密钥与环境变量)。
  • 上传 dist/。 里面有产物和 SHA256SUMS。
  • 用 --json 和退出码决定下一步(退出码与 JSON)。

没有 TTY 时,进度动画和颜色会关闭,每 60 秒输出一行心跳,避免 CI 因长时间无输出而超时。

Android#

jobs:
  android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: dart pub global activate fpack 1.1.16 && echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
      - run: fpack build apk aab --split-per-abi=both
        env:
          FPACK_ANDROID_KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
          FPACK_ANDROID_KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
          FPACK_ANDROID_KEY_ALIAS: upload
      - uses: actions/upload-artifact@v7
        with: { name: android, path: dist/ }

用 base64 -i upload.jks | pbcopy(Linux:base64 -w0 upload.jks)生成密钥内容。如果密钥密码与密钥库密码不同,再设置 FPACK_ANDROID_KEY_PASSWORD。fpack 会把密钥库以 0600 权限写到 build/fpack/secrets/,构建后删除。详情:Android。

iOS 与 macOS#

  apple:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: dart pub global activate fpack 1.1.16 && echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
      - run: fpack build ipa dmg --json > result.json

已签名并公证的 macOS 构建需要在临时钥匙串里准备证书,以及公证凭证:macOS:为 CI 导出证书里有完整的导入步骤(用 App Store Connect API 密钥)。如果不想在 Apple 处理期间占着 runner,可以用 --notarize-no-wait,之后再运行 fpack notarize finish。

Windows#

  windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: dart pub global activate fpack 1.1.16
      - run: fpack build windows exe

GitHub 的 Windows runner 预装了 Inno Setup;代码签名时,把 .pfx 做成 base64 存入密钥,在 runner 上解码(Windows)。

Linux 与 Web#

  linux:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: subosito/flutter-action@v2
      - run: sudo apt-get install -y ninja-build libgtk-3-dev rpm
      - run: dart pub global activate fpack 1.1.16 && echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
      - run: fpack build linux deb rpm web

在 ubuntu-24.04 上构建 snap 时,设置 linux.snap.build_mode: destructive;arm64 的 snap 用 ubuntu-24.04-arm(Linux)。

小技巧#

  • 缓存核心:原生核心(约 4 MB)每个版本只下载一次,存放在 ~/.cache/fpack(Linux)、~/Library/Caches/fpack(macOS)或 %LOCALAPPDATA%\fpack(Windows)。缓存这个目录就能跳过下载。
  • 机器可读的结果:fpack build … --json > result.json 会写出每个产物的路径、大小、SHA-256 和公证状态;人类可读的输出走 stderr。
  • 尽早失败:退出码 3 表示缺少前置条件,什么都没构建。
  • 每次运行一个版本:传 --build-number "$GITHUB_RUN_NUMBER",重跑就不会与已有产物冲突(版本)。
  • 先预览:在 pull request 里运行 fpack build --all --dry-run,可以看到发布会做什么。