macOS 公证(notarization)

口径说明

融云公开文档不覆盖 macOS 原生 SDK 与桌面交付链(dmg / 代码签名 / 公证 / 分发 / Gatekeeper);本页为本项目按 Apple 与 Electron 官方实践补齐的接入文档。

公证是 Apple 对分发包的自动安全检查:把已签名的 `.app`(或 `.dmg`)上传到 Apple 公证服务,审核通过后把票据 stapling 到包上。没有公证的包在其它 Mac 上会被 Gatekeeper 拦截。

前置条件​

  • 已用 Developer ID Application 证书签名,并开启 hardened runtime(`--options runtime`)。
  • Apple Developer 账号已加入开发者计划,知道 Team ID。
  • 生成 App 专用密码(Apple ID 管理页 → 安全 → App 专用密码),不要用账号主密码。
  • 网络可访问 `apple.com` 公证服务;CI 上需要放行出站 HTTPS。

方式一:notarytool(推荐)​

Shell
# 1) 先打 zip(公证接受 .zip / .dmg / .pkg)
ditto -c -k --keepParent "dist/mac/My Desktop.app" "dist/My Desktop.zip"

# 2) 提交并等待结果(首次通常 1~5 分钟)
xcrun notarytool submit "dist/My Desktop.zip" \
  --apple-id "you@example.com" \
  --team-id "ABCDE12345" \
  --password "app-specific-password" \
  --wait

# 3) 成功后将票据 stapling 到 .app(离线也能通过 Gatekeeper)
xcrun stapler staple "dist/mac/My Desktop.app"

# 4) 验证
spctl -a -vvv "dist/mac/My Desktop.app"
xcrun stapler validate "dist/mac/My Desktop.app"

方式二:electron-builder 自动公证​

Shell
# 通过环境变量提供凭据,electron-builder 会在签名后自动提交公证并 stapling
export APPLE_ID="you@example.com"
export APPLE_APP_SPECIFIC_PASSWORD="app-specific-password"
export APPLE_TEAM_ID="ABCDE12345"

npx electron-builder --mac --x64 --arm64

dmg 的公证​

如果只公证 `.app`,dmg 内的应用仍带票据;更稳妥的做法是对最终 dmg 再提交一次公证并 stapling,确保用户挂载 dmg 后首次启动即通过。

Shell
xcrun notarytool submit "dist/My Desktop-0.1.0.dmg" \
  --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD" --wait

xcrun stapler staple "dist/My Desktop-0.1.0.dmg"
xcrun stapler validate "dist/My Desktop-0.1.0.dmg"

查看公证日志​

Shell
# 提交失败时,用返回的 id 拉取详细日志
xcrun notarytool log <submission-id> \
  --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD"

# 历史提交
xcrun notarytool history --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD"

常见失败原因​

日志关键字原因处理
`The binary is not signed with a valid Developer ID certificate`用了 ad-hoc 或开发证书改用 Developer ID Application 证书
`The executable does not have the hardened runtime enabled`未开启 hardened runtime签名加 `--options runtime`
`The signature does not include a secure timestamp`缺时间戳`codesign --timestamp`
`The bundle is damaged` / `Invalid`嵌套组件签名不一致重新打包,避免手改包内容
`You must first sign the relevant documents`凭据错误或未同意协议检查 App 专用密码与开发者协议状态
公证不是“签名替代品”

顺序固定为:签名 → 公证 → stapling → 验证。任何一步重做后都要重新走完整链路。