使用 xcodebuild 和 asc 对 macOS 应用进行归档、导出与公证。适用于需要通过 Developer ID 签名和 Apple 公证准备在 App Store 之外独立分发的 macOS 应用场景。
macOS 应用公证 (macOS Notarization)
当需要对 macOS 应用进行公证以在 App Store 之外独立分发时,请使用此 Skill。
前置条件
- 已安装 Xcode 并配置好命令行工具 (Command Line Tools)。
- 已配置身份认证(通过
asc auth login或ASC_*环境变量)。 - 本地 Keychain 中存在有效的 Developer ID Application 证书。
- 应用的 Xcode 项目能够正常构建 macOS 版本。
预检:验证签名身份
在开始归档之前,确认本地存在有效的 Developer ID Application 签名身份:
security find-identity -v -p codesigning | grep "Developer ID Application"
如果未找到身份,请前往 https://developer.apple.com/account/resources/certificates/add 手动创建(App Store Connect API 不支持创建 Developer ID 证书)。
修复异常的信任设置
如果 codesign 或 xcodebuild 报 "Invalid trust settings" 或 "errSecInternalComponent" 错误,可能是证书被设置了自定义信任重写,从而破坏了证书链:
# 检查是否存在自定义信任设置
security dump-trust-settings 2>&1 | grep -A1 "Developer ID"
# 如果存在重写项,导出证书并清除自定义设置
security find-certificate -c "Developer ID Application" -p ~/Library/Keychains/login.keychain-db > /tmp/devid-cert.pem
security remove-trusted-cert /tmp/devid-cert.pem
验证证书链
修复信任设置后,验证证书链是否完整:
codesign --deep --force --options runtime --sign "Developer ID Application: YOUR NAME (TEAM_ID)" /path/to/any.app 2>&1
正确的签名证书链必须依次显示:Developer ID Application → Developer ID Certification Authority → Apple Root CA。
第 1 步:归档 (Archive)
xcodebuild archive \
-scheme "YourMacScheme" \
-configuration Release \
-archivePath /tmp/YourApp.xcarchive \
-destination "generic/platform=macOS"
第 2 步:使用 Developer ID 导出
创建一个用于 Developer ID 分发的 ExportOptions plist 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>automatic</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
</dict>
</plist>
导出归档文件:
xcodebuild -exportArchive \
-archivePath /tmp/YourApp.xcarchive \
-exportPath /tmp/YourAppExport \
-exportOptionsPlist ExportOptions.plist
这会生成一个已使用 Developer ID Application 签名且带有安全时间戳的 .app 包。
验证导出结果
codesign -dvvv "/tmp/YourAppExport/YourApp.app" 2>&1 | grep -E "Authority|Timestamp"
确认满足以下两点:
- 证书链开头为 "Developer ID Application"
- 包含时间戳 (Timestamp)
第 3 步:打包成 ZIP 以供公证
ditto -c -k --keepParent "/tmp/YourAppExport/YourApp.app" "/tmp/YourAppExport/YourApp.zip"
第 4 步:提交公证
异步提交(无需等待)
asc notarization submit --file "/tmp/YourAppExport/YourApp.zip"
同步等待公证结果
asc notarization submit --file "/tmp/YourAppExport/YourApp.zip" --wait
自定义轮询间隔与超时
asc notarization submit --file "/tmp/YourAppExport/YourApp.zip" --wait --poll-interval 30s --timeout 1h
第 5 步:检查公证结果
查看状态
asc notarization status --id "SUBMISSION_ID" --output table
查看开发者日志(公证失败时使用)
asc notarization log --id "SUBMISSION_ID"
获取日志 URL 以查看详细问题:
curl -sL "LOG_URL" | python3 -m json.tool
列出历史提交记录
asc notarization list --output table
asc notarization list --limit 5 --output table
第 6 步:装订公证票据 (Staple)(可选)
公证成功后,将公证票据装订到应用上,以便应用支持离线运行:
xcrun stapler staple "/tmp/YourAppExport/YourApp.app"
若通过 DMG 或 PKG 形式分发,需在创建镜像/安装包后再进行装订:
# 创建 DMG 镜像
hdiutil create -volname "YourApp" -srcfolder "/tmp/YourAppExport/YourApp.app" -ov -format UDZO "/tmp/YourApp.dmg"
xcrun stapler staple "/tmp/YourApp.dmg"
支持的文件格式
| 格式 | 使用场景 |
|---|---|
.zip |
最简单;将已签名的 .app 包压缩即可 |
.dmg |
磁盘镜像,方便用户拖拽安装 |
.pkg |
安装包(需要 Developer ID Installer 证书) |
PKG 安装包公证
如需公证 .pkg 文件,需要准备 Developer ID Installer 证书(与 Developer ID Application 证书区分开)。此证书无法通过 App Store Connect API 生成,必须前往 https://developer.apple.com/account/resources/certificates/add 手动创建。
为安装包签名:
productsign --sign "Developer ID Installer: YOUR NAME (TEAM_ID)" unsigned.pkg signed.pkg
然后提交公证:
asc notarization submit --file signed.pkg --wait
常见问题排查
导出时提示 "Invalid trust settings"
Developer ID 证书包含了自定义信任重写设置。请参阅上方的“预检”章节进行清除。
提示 "The binary is not signed with a valid Developer ID certificate"
应用使用了 Development 或 App Store 证书签名。请检查 ExportOptions.plist,确保 method 设为 developer-id 后重新导出。
提示 "The signature does not include a secure timestamp"
如果手动调用 codesign,请加上 --timestamp 参数;或者直接使用 xcodebuild -exportArchive,它会自动包含安全时间戳。
大文件上传超时
可以调大上传超时限制:
ASC_UPLOAD_TIMEOUT=5m asc notarization submit --file ./LargeApp.zip --wait
公证返回 "Invalid"(无效),但签名看上去没问题
拉取开发者日志获取具体的错误提示:
asc notarization log --id "SUBMISSION_ID"
常见原因:嵌套的二进制文件未签名、缺少 hardened runtime(硬化运行时)、嵌入的动态库缺少时间戳。
注意事项
asc notarization系列命令基于 Apple Notary API v2,而非xcrun notarytool。- 身份认证与其它
asc命令共用相同的 API 密钥。 - 文件会通过流式传输直接上传至 Apple 的 S3 存储桶(无需在本地占用全量文件缓存)。
- 超过 5 GB 的文件会自动开启分块并行上传 (multipart upload)。
- 建议随时使用
--help查看可用参数:asc notarization submit --help。






