SuperAPI AI 工具集

apple-mac-cicd

部署与运维

查看项目

更新于 10-16 06:54

技能介绍

Apple macOS CI/CD 与自动更新

该技能提供通过 GitHub Actions 发布已签名并公证的 macOS 应用的专家工作流,并支持自动更新。内容基于工作区中的 Cometrans(原生 Swift)与 Cometode(Electron)两个参考项目。

参考项目

应用 技术栈 发布触发 自动更新
Cometrans Swift CLI → .app + DMG workflow_dispatch 并输入版本 构建号已为 Sparkle 就绪(尚未接入)
Cometode Electron + Svelte 推送 tag v* electron-updater + latest-mac.yml

实现时可参考的资料文件包括:Cometrans 模式、Cometode 模式、GitHub secrets、自动更新指南。

思考流程

第一步:确定应用类型

目标:选择正确的发布与更新技术栈。

决策矩阵:

应用类型 构建工具 CI 运行器 更新器
原生 Swift / SwiftPM build_dmg.sh 或 Xcode macos-26(通过 DEVELOPER_DIR 固定 Xcode) Sparkle + appcast
Electron + electron-builder pnpm build:mac macos-latest electron-updater + GitHub Releases

决策点:明确说明“这是 [原生|Electron] 应用;更新器将使用 [Sparkle|electron-updater]。”

第二步:Apple 开发者前置条件

目标:在改动 CI 之前,确保签名与公证凭据已存在。

清单:

  • Apple Developer Program 会员资格
  • Developer ID Application 证书(非 Mac App Store)
  • 导出 .p12 并做 base64 编码以供 CI 使用
  • 在 appleid.apple.com 生成 App 专用密码(供 notarytool 使用)
  • 从 developer.apple.com 获取 Team ID

操作:

  • 运行 bash /mnt/skills/user/apple-mac-cicd/scripts/validate-secrets.sh 审计本地环境变量
  • 配置 GitHub 仓库 secrets(见 github-secrets.md)

第三步:本地构建脚本

目标:一个脚本即可在本地与 CI 中产出一致且已签名的构建产物。

原生(Cometrans 模式):

  • build_dmg.sh 构建 Swift release,组装 .app,使用 --options runtime 进行 codesign,创建 DMG
  • CFBundleVersion 按 major10000 + minor100 + patch 推导,用于 Sparkle 的语义化版本比较
  • NOTARIZE=1 时通过 xcrun notarytool submit --wait + stapler staple 触发 scripts/notarize.sh

Electron(Cometode 模式):

  • electron-builder.yml:hardenedRuntime: true、notarize: true、publish: github
  • mac 目标:dmg + zip(electron-updater 需要 zip)
  • Entitlements 放在 build/entitlements.mac.plist(Electron 需要 JIT、unsigned executable memory)

第四步:GitHub Actions 发布工作流

目标:CI 完成构建、签名、公证并发布到 GitHub Releases。

原生工作流结构(Cometrans .github/workflows/release.yml):

  • prepare job — 解析版本,创建/推送 tag
  • build job — 将 P12 导入临时 keychain,运行 ./build_dmg.sh,上传产物
  • release job — 下载产物,使用 softprops/action-gh-release 附带 DMG + sha256

Electron 工作流结构(Cometode .github/workflows/release.yml):

  • 触发条件:push: tags: ['v*']
  • 从 tag 同步 package.json 版本
  • 带签名环境变量运行 pnpm build:mac
  • 上传 dist/.dmg、dist/.zip、dist/*.blockmap、dist/latest-mac.yml(自动更新必需)

按技术栈所需的 secrets:

Secret 原生 Electron
APPLE_DEVELOPER_ID_P12_BASE64 ✓ —
APPLE_DEVELOPER_ID_P12_PASSWORD ✓ —
KEYCHAIN_PASSWORD ✓ —
DEVELOPER_ID_APPLICATION ✓ —
CSC_LINK — ✓(base64 p12)
CSC_KEY_PASSWORD — ✓
APPLE_ID ✓ ✓
APPLE_APP_SPECIFIC_PASSWORD ✓ ✓
APPLE_TEAM_ID ✓ ✓

第五步:自动更新集成

目标:用户无需手动下载 DMG 即可获得更新。

Electron(Cometode — 已完整接通):

  • electron-updater 从 GitHub Releases 读取 latest-mac.yml
  • electron-builder.yml 的 publish.provider: github 必须与仓库 owner/name 匹配
  • 主进程:autoUpdater.autoDownload = true,启动时以及每 4 小时检查一次
  • 发布工作流必须附带 latest-mac.yml、.zip 与 .blockmap
  • 仅在生产环境启用(if (!is.dev))

原生(Cometrans — 构建号已就绪,Sparkle 待接入):

  • build_dmg.sh 已设置 CFBundleVersion 以供 Sparkle 比较
  • 待完成:添加 Sparkle SPM 依赖、在 Info.plist 配置 SUFeedURL、EdDSA 签名密钥
  • CI 需在每次发布时生成/签名 appcast XML 并与 DMG 一起发布

详见 auto-updater.md。

第六步:PR 的 CI 工作流

目标:在发布前捕获构建中断。

  • 原生:在 push/PR 触发 ci.yml — 在 macos-26 上执行 swift build -c release && swift test
  • Electron:添加 ci.yml,执行 pnpm typecheck && pnpm build(CI 无需签名)

第七步:发布与验证

目标:发布并端到端确认自动更新可用。

发布清单:

  • 在源码中升级版本(version.txt 或 package.json)
  • 打 tag vX.Y.Z(Electron)或运行 workflow_dispatch(Cometrans)
  • CI 完成签名 + 公证
  • GitHub Release 包含所有必需资产
  • 安装旧版本,确认更新器能找到新版本
  • 对下载的产物执行 spctl -a -vv -t install 通过

本地验证公证:

xcrun stapler validate Cometrans-1.0.0.dmg
# 或
spctl -a -vv -t install dist/cometode-1.0.0-arm64.dmg

用法

验证本地是否已配置 secrets:

bash /mnt/skills/user/apple-mac-cicd/scripts/validate-secrets.sh

生成发布工作流脚手架:

bash /mnt/skills/user/apple-mac-cicd/scripts/scaffold-release-workflow.sh \
  --type electron \
  --app-name MyApp \
  --output .github/workflows/release.yml

参数:

  • --type — native 或 electron(必填)
  • --app-name — 产物名称主干,例如 Cometrans(必填)
  • --output — 工作流文件路径(默认:.github/workflows/release.yml)

向用户呈现结果

协助搭建 macOS CI/CD 时,报告:

  • 应用类型与所选更新器
  • 仍缺失的 secrets(运行 validate 脚本输出)
  • 创建/修改的文件及路径
  • 发布步骤 — 如何触发首次发布
  • 自动更新状态 — 已接通或剩余步骤

故障排查

CI 报“No signing certificate configured”

  • 确认 APPLE_DEVELOPER_ID_P12_BASE64 / CSC_LINK secret 已设置且能解码为有效 P12

公证因凭据无效失败

  • 重新生成 App 专用密码;确认 APPLE_TEAM_ID 与证书匹配

CI 成功但 Gatekeeper 仍拦截应用

  • 确保原生 codesign 使用 --options runtime,或 Electron 使用 hardenedRuntime: true
  • 确认已运行 stapler:xcrun stapler validate <artifact>

electron-updater 找不到更新

  • 发布必须包含 latest-mac.yml、.zip、.blockmap
  • electron-builder.yml 中的 publish.owner / publish.repo 必须与 GitHub 仓库匹配
  • 应用必须以生产模式构建(非 dev)

Sparkle 版本顺序错误

  • 使用数字型 CFBundleVersion(Cometrans 公式:major10000 + minor100 + patch)
  • 切勿在 CFBundleVersion 中使用 semver 字符串