What's new in notarization for Mac apps
System & Services 进阶 20m

Mac App 公证新变化

What's new in notarization for Mac apps

2022年6月6日

在 Apple 官方观看视频

一句话判断

公证流程迎来了全面现代化——altool 退役、Xcode 14 内置公证提速 4 倍、新的 REST API 支持直接上传 S3 和 webhook 回调,终于不用再轮询等待结果了。

这场 Session 讲了什么

这场 Session 围绕 macOS App 公证(notarization)流程的三个层面讲了变化:工具链更新、API 现代化、以及工作流集成。

altool 退役。 用了多年的 altool --notarize-app 命令将在 2023 年秋天正式退役。替代方案有两个:Xcode 14 的内置公证流程和新的 REST API(notarytool)。如果你还在用 altool 的 CI 脚本,现在就该迁移了。

Xcode 14 内置公证提速。 Xcode 14 把公证流程集成到了 Archive 流程里。你只需要在 Organizer 里点击 “Distribute App”,选择公证选项,Xcode 会自动完成签名、上传、等待审核、装订(stapling)整个流程。Apple 声称速度提升了 4 倍——从提交到拿到结果,之前可能要等几分钟甚至十几分钟,现在通常不到一分钟。

新的 REST API(notarytool)。 这是给 CI/CD 管线用的。notarytool 是一个命令行工具(Xcode 自带),底层调用 Apple 的 Notary API。它支持 JWT(JSON Web Token)认证,不再需要 App-specific password。认证流程是:用你的 Apple ID 生成一个 JWT token,然后用这个 token 调用 API。

S3 上传。 新的 Notary API 支持直接上传到 Apple 提供的 S3 bucket。之前的流程是把整个 App 压缩包上传到 Apple 的服务器,对于大型 App 来说上传很慢。新的流程是先调用 API 获取一个预签名的 S3 URL,然后用这个 URL 上传到 S3。上传完成后通知 Apple 开始审核。

Webhook 支持。 之前提交公证后需要轮询 API 检查状态,现在可以注册 webhook URL,Apple 审核完成后会主动 POST 通知你。这对 CI/CD 管线来说是一个巨大的改进——不再需要写 while true; sleep 30; notarytool check 这种轮询脚本了。

值得深挖的点

JWT 认证 vs App-specific password。 之前 altool 需要 App-specific password(在 appleid.apple.com 上生成的那个),安全性很一般——一旦泄露,别人可以用它做很多事情。JWT 认证方式更安全:你生成一个 API key(在 App Store Connect 的 Keys 页面),用这个 key 签发 JWT token。token 有过期时间,权限也受到 API key 的 scope 限制。即使 token 泄露,过期后就无效了。

S3 上传的性能优势。 对于超过 100MB 的 App,S3 上传的速度优势很明显。Apple 的 S3 bucket 使用了 CDN 加速,而且支持分片上传。你的 CI 脚本可以用 aws s3 cp 或者任何支持 S3 协议的工具来上传,不需要用 Apple 的专用上传协议。

代码片段

使用 notarytool 提交公证:

# 首先创建 API key(只需一次,在 App Store Connect 的 Integrations > App Store Connect API 页面)
# 获取 Issuer ID、Key ID 和 .p8 私钥文件

# 提交公证
notarytool submit "MyApp.zip" \
    --key "AuthKey.p8" \
    --key-id "YOUR_KEY_ID" \
    --issuer "YOUR_ISSUER_ID" \
    --wait

# --wait 会阻塞直到公证完成,并打印结果
# 如果不想等待,去掉 --wait,之后手动检查:
notarytool log <submission-id> \
    --key "AuthKey.p8" \
    --key-id "YOUR_KEY_ID" \
    --issuer "YOUR_ISSUER_ID"

在 CI 中使用 notarytool(GitHub Actions 示例):

- name: Notarize App
  env:
    NOTARY_API_KEY: ${{ secrets.NOTARY_API_KEY_P8_BASE64 }}
    NOTARY_KEY_ID: ${{ secrets.NOTARY_KEY_ID }}
    NOTARY_ISSUER: ${{ secrets.NOTARY_ISSUER }}
  run: |
    echo "$NOTARY_API_KEY" | base64 -d > AuthKey.p8
    # 构建 DMG 或 zip
    ditto -c -k --keepParent "MyApp.app" "MyApp.zip"
    # 提交并等待
    notarytool submit "MyApp.zip" \
      --key "AuthKey.p8" \
      --key-id "$NOTARY_KEY_ID" \
      --issuer "$NOTARY_ISSUER" \
      --wait
    # 装订公证票据
    xcrun stapler staple "MyApp.app"

最佳实践

迁移 CI 脚本时,优先使用 JWT 认证(API key 方式)而不是 Apple ID + App-specific password。JWT 方式不需要 2FA 交互,更适合自动化环境。而且 API key 不会过期(除非你主动撤销),比 App-specific password 更稳定。

对于大型 App(超过 200MB),使用 S3 上传方式。notarytool 默认会用 S3 上传,你不需要额外配置。如果你的 CI 环境网络到 Apple S3 bucket 的延迟很高,可以考虑用 --s3-accelerate 参数启用加速上传。

装订(stapling)是必须的步骤。公证通过后一定要跑 xcrun stapler staple,否则用户第一次打开 App 时需要联网验证。装订会把公证票据附加到 App 包里,让 macOS 可以离线验证。

还有什么值得关注

  • altool 退役的时间点是 2023 年秋天(配合 Xcode 15 的发布),所以你还有大约一年的迁移窗口。
  • notarytool 支持 --webhook 参数,可以指定一个 URL,公证完成后 Apple 会 POST 一个 JSON 通知。webhook 的请求体包含 submission ID 和状态(success/invalid)。
  • Xcode 14 的内置公证支持自动装订,不需要额外跑 stapler 命令。
  • 公证审核的速度提升主要来自 Apple 后端的基础设施升级,和你的 App 大小关系不大。之前大型 App 可能等很久,现在基本都在一分钟左右。
WWDC 2022