WWDC Quick Look 💓 By SwiftGGTeam
What’s new in notarization for Mac apps

What’s new in notarization for Mac apps

观看原视频

Highlight

Apple 给 macOS App 公证提供了三条迁移路径:altool 在 2023 年秋季停止用于公证,Xcode 14 接入 notarytool 后端,新的 Notary REST API 支持从 Linux 等 CI 环境提交和查询公证任务。


核心内容

Mac App 如果不走 App Store 分发,开发者通常要做 Developer ID 签名和公证。公证服务会分析上传的软件,帮助 macOS 在用户下载第三方软件时拦截恶意内容。

这套流程以前常见的痛点有两个。

第一,旧脚本还在调用 altool。团队要维护凭据、上传、等待结果和错误处理。第二,CI 机器不一定是 Mac。比如 Linux 构建节点可以产出归档文件,却不能直接运行 Xcode 或 notarytool 完成后续流程。

这场 session 给出明确迁移路线:旧的 altool 公证和 Xcode 13 UI 上传会在 2023 年秋季停止工作;Xcode 14 的图形流程改用 notarytool 同一套后端;新的 Notary REST API 让任何能联网的机器都能提交文件、查询状态、获取历史记录和详情。


详细内容

altool 退场,notarytool 继续可用

01:11)Apple 在 2021 年发布了 notarytool,作为 altool 公证流程的替代。2022 年这场 session 给出截止日期:使用 altool 做公证会在 2023 年秋季停止工作。Xcode 13 UI 上传到公证服务也会在同一截止日期后停止。

notarytool 本身会继续工作,包括 Xcode 13 内置的版本。Apple 仍建议升级,以获得最新修复和改进。

# 概念示意:旧脚本需要从 altool 迁到 notarytool
# 具体参数以 2021 年 “Faster and simpler notarization for Mac apps” 和文档为准。

# before: xcrun altool ...
# after:  xcrun notarytool ...

关键点:

  • 第一行说明这是迁移提示,不是本场 session 给出的完整命令。
  • altool 是需要迁出的旧路径。
  • notarytool 是 2023 年秋季之后仍可继续使用的命令行路径。
  • 具体迁移细节在 Apple 引用的 WWDC 2021 session 中展开。

Xcode 14 把图形流程接到 notarytool 后端

02:30)如果团队使用 Xcode Organizer 上传公证,迁移压力更小。Xcode 14 的内置公证支持迁到了和 notarytool 相同的后端,因此能获得 Apple 在 2021 年为 notarytool 宣布的约 4 倍性能提升。

这部分的重点是“不改工作流”。演讲明确说,除了更新 Xcode,通常不需要改变项目设置或现有流程。

Xcode 13 UI notarization  ->  stops working after fall 2023
Xcode 14 UI notarization  ->  uses the notarytool backend
notarytool CLI            ->  continues past the deadline

关键点:

  • Xcode 13 UI notarization 对应演讲中会在截止日期后停止工作的旧 UI 上传方式。
  • Xcode 14 UI notarization 对应新的 Xcode 集成。
  • notarytool backend 是 Xcode 14 获得性能提升的原因。
  • notarytool CLI 仍是自动化脚本可使用的迁移目标。

Notary REST API:先创建提交,再上传到 S3

03:01)新的 Notary REST API 是这场 session 的主角。它是 JSON Web 服务,使用 JSON Web Token(JWT)认证,和其他 App Store Connect API 类似。它的目标是让不运行 macOS 的机器也能和公证服务交互。

上传分两步。第一步,把文件名和 SHA-256 发给 Notary API。服务返回临时 S3 凭据、bucket、object,以及一个用于跟踪流程的 submission_id。第二步,用 S3 SDK 把文件上传到 Apple 提供的位置。

# Upload file for notarization

def upload_file(token, filepath, sha256):
    data = { "sha256": sha256, "submissionName": os.path.basename(filepath) }
    resp = requests.post(
       "https://appstoreconnect.apple.com/notary/v2/submissions",
        json=data,
        headers={"Authorization": "Bearer " + token})

    output = resp.json()
    aws_info = output["data"]["attributes"]
    submission_id = output["data"]["id"] 

    client = boto3.client(
        "s3",  
        aws_access_key_id=aws_info["awsAccessKeyId"],
        aws_secret_access_key=aws_info["awsSecretAccessKey"],
        aws_session_token=aws_info["awsSessionToken"])
    client.upload_file(filepath, aws_info["bucket"], aws_info["object"])

关键点:

  • upload_file(token, filepath, sha256) 把 JWT、文件路径和文件哈希作为输入。
  • data 只包含演讲里提到的基础文件信息:SHA-256 和提交名称。
  • requests.post(...) 调用 Notary REST API 的 submissions endpoint。
  • Authorization: Bearer ... 使用 JWT 认证。
  • aws_info 保存响应中的临时 S3 上传信息。
  • submission_id 是后续查询公证状态的 ID。
  • boto3.client("s3", ...) 用返回的临时凭据创建 S3 客户端。
  • client.upload_file(...) 把文件上传到响应指定的 bucket 和 object。

这段代码也说明了 REST API 的边界:Notary API 不直接接收整个文件。它先创建提交并返回上传信息,文件内容再走 Amazon S3。

查询状态:等待 In Progress 变成最终结果

06:12)上传之后,分发前要确认公证服务已经处理完提交。REST API 的直接做法是用 submission_id 查询状态。状态会保持 In Progress,直到处理完成后变为最终状态,例如 AcceptedInvalid

# Wait for completion

def watch_upload(submission_id, token):
    while True:
        resp = requests.get(
            "https://appstoreconnect.apple.com/notary/v2/submissions/" + submission_id, 
            headers={"Authorization": "Bearer " + token})

        output = resp.json()
        current_status = output["data"]["attributes"]["status"]
        
        if current_status != "In Progress":
            return current_status # For example: Accepted or Invalid

        time.sleep(30) # Allow time for submission to progress

关键点:

  • watch_upload(submission_id, token) 用上传阶段拿到的提交 ID 继续跟踪同一次提交。
  • requests.get(...) 访问单个 submission 的 Notary API endpoint。
  • Authorization header 继续使用同一个 JWT 认证方式。
  • current_status 读取响应里的当前处理状态。
  • current_status != "In Progress" 表示公证服务已经给出最终结果。
  • AcceptedInvalid 是演讲中列出的最终状态示例。
  • time.sleep(30) 避免持续请求;演讲示例用 30 秒等待提交推进。

演讲还补充,提交完成后,可以通过 API 获取这次上传的公证日志。具体 endpoint 需要看 Notary API 文档。

Webhook:把上传系统和后续自动化解耦

06:49)轮询不是唯一选择。Notary REST API 也支持 webhook 工作流:初始上传请求里提供 webhook URL,自动分析结束、票据创建、最终状态保存后,公证服务会调用这个 URL。

演讲明确说明,通知内容包含 submission IDteam ID 和一个用于验证通知来自 Apple 的签名。

upload request includes webhook URL


notary service analyzes submission


tickets are created and final status is saved


notary service calls webhook URL

        ├─ submission ID
        ├─ team ID
        └─ signature

关键点:

  • webhook URL 是在初始上传请求中提供的回调地址。
  • analyzes submission 对应公证服务对上传文件的自动分析。
  • tickets are created 对应演讲中分析完成后创建 ticket 的步骤。
  • final status is saved 表示服务端已经有最终公证状态。
  • submission IDteam ID 让接收方知道是哪次提交、哪个团队。
  • signature 用来验证通知来源。

这个模型适合 CI/CD。上传机器只负责提交文件。另一个系统收到 webhook 后,可以通知提交者,也可以启动自动分发流程。两部分不必用同一个进程等待。


核心启发

  • 做什么:把仍在使用 altool 的 CI 脚本列出来,逐个迁移到 notarytool 或 Notary REST API。
    为什么值得做:altool 公证会在 2023 年秋季停止工作,迁移是硬性期限。
    怎么开始:先找构建日志里的 altool 调用,再按是否能运行 macOS 选择 notarytool 或 REST API。

  • 做什么:给 Linux 构建节点增加一个公证上传步骤。
    为什么值得做:REST API 支持从任何联网机器提交,不再要求上传步骤运行在 Mac 上。
    怎么开始:用 JWT 调用 POST https://appstoreconnect.apple.com/notary/v2/submissions,拿到 S3 信息后用现有语言的 S3 SDK 上传文件。

  • 做什么:为公证结果建立 webhook 回调服务。
    为什么值得做:webhook 可以把上传流程和后续通知、分发流程拆开,减少长时间轮询任务。
    怎么开始:在初始提交请求中配置 webhook URL;接收通知后校验签名,再根据 submission ID 查询或触发后续动作。

  • 做什么:把公证状态和日志接入内部发布面板。
    为什么值得做:REST API 支持查询提交状态、历史记录、提交详情和公证日志,发布人员不用只看 CI 控制台。
    怎么开始:保存每次上传返回的 submission_id,定时或按需调用 Notary API 展示状态和日志链接。


关联 Session

评论

GitHub Issues · utterances