用途
该技能把 iOS 源码树一路推进到磁盘上一个已签名、已验证的 .ipa,供后续上传使用。它明确止步于本地验证产物,不负责上传;TestFlight 与 App Store 的发布交由 app-store-publish 技能。相关自动化入口包括:/mobile-release:ship-beta 端到端运行本技能并上传结果,/mobile-release:bootstrap 从零搭建签名与 CI,/mobile-release:doctor 诊断损坏的签名配置。
主要能力
- 确认主机为 macOS 且安装真实 Xcode,并固定 Xcode 版本。
- 发现项目:区分 workspace 与 project,识别 scheme、configuration、解析后的 build settings 以及所有内嵌 bundle。
- 设置版本与构建号,要求 CURRENT_PROJECT_VERSION 严格高于该营销版本已上传的每一个构建号。
- 确认签名材料:证书、描述文件、entitlements,以及自动签名与手动签名的选择。
- 配置 App Store Connect API 密钥,环境变量名需逐字符一致。
- 在 CI 上创建钥匙串并导入身份,按指定顺序执行。
- 团队跨机器共享签名材料时可使用 match,但采用前需先撤销现有证书。
- 归档与导出,method 取值需以本机 xcodebuild -help 输出为准。
- 上传前验证 .ipa,未引用 Authority= 行不得报告构建完成。
- 提供 GitHub Actions 工作流,失败时先查 troubleshooting 再改构建。
使用方式
主机检查命令:
uname -s # must print: Darwin
sw_vers # macOS product and build version
xcode-select -p # must be an Xcode.app path, not /Library/Developer/CommandLineTools
xcodebuild -version # e.g. Xcode 16.4
若 xcode-select -p 输出 /Library/Developer/CommandLineTools,说明只装了命令行工具,无法归档。CI 上可用 sudo xcode-select -s /Applications/Xcode_16.4.app 固定版本。
项目发现命令:
ls -d *.xcworkspace *.xcodeproj 2>/dev/null # a Podfile or .xcworkspace means use -workspace
xcodebuild -list -json -workspace MyApp.xcworkspace
xcodebuild -showBuildSettings -json \
-workspace MyApp.xcworkspace -scheme MyApp -configuration Release \
-destination 'generic/platform=iOS' > /tmp/buildsettings.json
归档与导出命令:
set -euo pipefail; set -o pipefail
NSUnbufferedIO=YES xcodebuild \
-workspace MyApp.xcworkspace -scheme MyApp -configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "$PWD/build/MyApp.xcarchive" \
CURRENT_PROJECT_VERSION="$BUILD_NUMBER" \
archive 2>&1 | tee build/archive.log | xcbeautify
NSUnbufferedIO=YES xcodebuild -exportArchive \
-archivePath "$PWD/build/MyApp.xcarchive" \
-exportPath "$PWD/build/export" \
-exportOptionsPlist "$PWD/ExportOptions.plist" \
-allowProvisioningUpdates \
-authenticationKeyPath "$PWD/private_keys/AuthKey_ABC1234567.p8" \
-authenticationKeyID ABC1234567 \
-authenticationKeyIssuerID 6053b7fe-68a8-4acb-89be-165aa6465141 \
2>&1 | tee build/export.log | xcbeautify
验证命令:
unzip -q build/export/MyApp.ipa -d /tmp/v && APP="$(echo /tmp/v/Payload/*.app)"
codesign -dv --verbose=4 "$APP" # Authority, Identifier, TeamIdentifier
codesign --verify --deep --strict --verbose=2 "$APP"
codesign -d --entitlements :- "$APP"
security cms -D -i "$APP/embedded.mobileprovision" | plutil -p -
/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$APP/Info.plist"
ls build/MyApp.xcarchive/dSYMs/ # dSYMs are NOT inside the .ipa
适用场景
- 在 macOS 或 macOS CI runner 上为 iOS 应用生成发布用已签名 .ipa。
- 需要固定 Xcode 版本、统一构建号、管理多 bundle(widget、extension、watch app、App Clip)签名的发布流程。
- 团队使用 match 跨机器共享签名材料,或需要在 CI 中创建钥匙串并导入身份。
- 上传前需要验证签名身份、entitlements、描述文件与 dSYM 的场景。
限制
- 必须为 macOS 且安装真实 Xcode;Linux、Docker、WSL 无法产出已签名 .ipa。若主机为 Linux,应说明并停止;可选方案为 macOS CI runner、Xcode Cloud 或通过 SSH 连接 Mac。
- 本技能不执行上传,上传属于 app-store-publish 技能。
- ExportOptions.plist 的 method 取值随已安装 Xcode 变化,旧名称(app-store、ad-hoc、development)已弃用,需以本机 xcodebuild -help 输出为准。
- 构建号不可复用,且构建号位于已签名二进制内。
- 不得将 .p8、.p12、MATCH_PASSWORD 或钥匙串密码打印到日志;.p8 仅可下载一次,泄露需立即在 App Store Connect 撤销。
- 资料中标注:ExportOptions.plist 的 method 取值列表仅为 [snippet];描述文件类型及其一年有效期、manageAppVersionAndBuildNumber、agvtool、match 子命令列表与命名、codesign 输出形态均为 [unverified];作者环境为 Linux 无 Xcode,未实际执行,首次真实运行即为测试。