用 Developer ID 自主分发意味着什么
将 macOS 应用交付给用户,大致有两条路。一条是通过 Mac App Store (MAS),另一条是由开发者自行制作 .dmg(或 .app)文件,让用户从网站或 GitHub 等地方下载的直接分发 (direct distribution)。
直接分发有明显的优势:不必等待 App Store 审核,没有支付手续费,可以随时以自己想要的方式发布更新。但相应地,原本由 App Store 代劳的事情——代码签名、公证 (notarization)、自动更新——都需要开发者自行搭建。
如果不搭建这些,macOS 的安全机制 Gatekeeper 会阻止应用启动。用户第一次打开应用时会看到类似"无法打开该 App,因为它来自身份不明的开发者"的警告,大多数用户就此放弃安装。要让应用像正规分发的应用那样双击即可打开,就必须用 Developer ID 证书签名应用,并获得 Apple 的公证。
本系列介绍的正是这套一次性准备流程。好消息是,这里涉及的配置大多只需做一次,即可在所有后续发布中复用。
本系列将完成的内容
共三篇,逐步搭建以下内容:
- (第 1 篇,本文) Developer ID Application 证书 + 公证用凭据
- (第 2 篇) 用于 Sparkle 自动更新的 EdDSA 签名密钥
- (第 3 篇) 托管更新 Feed 的公开仓库 + 收尾构建配置
系列结束时,你应该已经准备好以下内容。现在先浏览一下清单,每篇逐一完成即可。
- macOS 钥匙串 (Keychain) 中的
Developer ID Application证书 - 存储在钥匙串中的公证用凭据配置文件
- 用于 Sparkle 更新签名的 EdDSA 密钥对(公钥 + 私钥)
- 私钥备份到安全位置
- 用于托管更新 Feed (appcast) 的公开 GitHub 仓库 + GitHub Pages
- 构建配置文件 (
ExportOptions.plist) 与应用侧配置
示例应用 — FocusTimer
本系列以虚构的 macOS 应用 FocusTimer(一款管理专注时间的简单计时器应用)为例。命令和路径中出现的 FocusTimer、Bundle Identifier com.example.FocusTimer、域名 example.com、证书名称、Team ID 等均为示例值。实际操作时请替换为你自己的应用名称和账户信息。
本文基于 Xcode 26 和 Sparkle 2.x(自动更新框架,第 2 篇中会用到)编写。Apple 时常调整界面布局和菜单位置,若按钮名称略有不同,整体流程不变。
前提条件 — 命令行工具
首先安装构建和发布自动化所需的两个命令行工具。前提是已安装 macOS 包管理器 Homebrew。
brew install gh create-dmg
gh— GitHub 官方 CLI,稍后用于创建 GitHub Release。create-dmg— 用于制作分发用.dmg磁盘镜像的工具,同时生成引导用户将应用拖入Applications文件夹的界面。
虽然现在还用不到,但发布自动化脚本通常会在开头检查这些工具是否存在,找不到就立即终止,因此提前安装好。
第 1 步 — 确认 Apple Developer Program
要申请 Developer ID 证书并对应用进行公证,需要 Apple Developer Program 会员资格。个人账户每年收费 $99。
如果已加入,只需确认状态是否为活跃即可。
- 访问 developer.apple.com/account
- 在 Membership details 部分确认状态为 Active
- 在同一页面记下你的 Team ID(示例中为
ABCDE12345),后续步骤中会反复用到。
若尚未加入,会员资格审批通常需要约一天时间。审批完成前无法申请证书,建议优先处理。
第 2 步 — 申请 Developer ID Application 证书
Developer ID Application 证书是对分发用 .app 和 .dmg 进行签名时使用的证书。macOS Gatekeeper 会将用此证书签名的应用识别为"已知开发者制作的应用"。
Apple 还有一种用于对
.pkg安装包签名的 Developer ID Installer 证书,两者不同。本系列以.dmg方式分发,因此只涉及 Application 证书。
申请流程
最简单的方式是通过 Xcode 操作。
- 启动 Xcode → 菜单 Xcode → Settings… (
⌘,) - 选择 Accounts 标签 → 在左侧列表中点击你的 Apple ID
- 点击右下角的 Manage Certificates… 按钮
- 在新弹出的窗口左下角点击
+按钮 - 从菜单中选择 Developer ID Application
- 一两秒后新证书出现在列表中,点击 Done
如此申请的证书会自动保存到 macOS 钥匙串 (Keychain) 中。证书与对应的私钥成对保存,有了这把私钥才能进行签名。
确认申请结果
在终端运行以下命令,确认证书是否已正确安装。
security find-identity -v -p codesigning | grep "Developer ID Application"
如果输出如下一行,则表示成功。
1) A1B2C3D4E5F6... "Developer ID Application: Gildong Hong (ABCDE12345)"
引号内的字符串是证书的正式名称。Gildong Hong 是注册在 Apple 账户中的姓名,括号内的 ABCDE12345 是第 1 步记下的 Team ID。这个名称在后续自动化代码签名时会原样使用,请再次核对。
证书续期
Developer ID 证书的有效期为 5 年。临近过期时,Xcode 的 Manage Certificates 列表中会显示 Expired。届时按照相同步骤重新申请新证书即可。
好消息是,已用旧证书签名并分发的应用不会在证书过期时立即失效。只有之后新建的构建才需要用新证书签名。因此无需过分担心过期问题。
第 3 步 — 注册用于公证的 App 专用密码
什么是公证 (notarization)
公证是在分发前将应用上传至 Apple 服务器进行恶意软件扫描的流程。通过扫描后,Apple 会颁发"公证票据",应用附带此票据后,Gatekeeper 才会无警告地开启应用。如果说签名证明"谁制作了它",那么公证就是"Apple 已扫描过一次"的独立证明流程。
公证提交使用 Apple 的 notarytool 命令,每次提交都会要求输入 Apple ID 密码。为避免每次手动输入,需要创建一个 App 专用密码 (App-Specific Password) 并提前存入钥匙串。
3-1. 申请 App 专用密码
App 专用密码是一种 16 位密码,用于替代主 Apple ID 密码,仅供特定用途使用。
- 访问 appleid.apple.com → 使用加入了 Apple Developer Program 的 Apple ID 登录(示例中为
[email protected]) - 登录与安全 (Sign-In and Security) → 选择 App 专用密码 (App-Specific Passwords)
- 点击
+按钮 → 输入密码名称(如focustimer-notarize) - 点击 创建 (Create) → 再次输入 Apple ID 密码
- 屏幕上显示
abcd-efgh-ijkl-mnop格式的 16 位密码。
关闭此页面后将无法再次查看该密码。 在进入下一步之前,请先将其复制到密码管理器等安全位置。
3-2. 存入 notarytool 配置文件
将申请到的密码保存为钥匙串配置文件。执行以下命令前,请将 --password 的值替换为刚才获得的实际密码。
xcrun notarytool store-credentials "focustimer-notarize" \
--apple-id "[email protected]" \
--team-id "ABCDE12345" \
--password "abcd-efgh-ijkl-mnop"
- 第一个参数
"focustimer-notarize"— 为此配置文件指定的名称,之后公证时将通过此名称加载凭据。 --apple-id— Apple Developer Program 账户的邮箱--team-id— 第 1 步中的 Team ID--password— 3-1 中申请的 App 专用密码
出现如下输出即为成功。
Credentials saved to Keychain.
凭据已存入钥匙串,App 专用密码的原始文本不再需要保留。(但若计划在其他电脑上也进行构建,建议保存在密码管理器中以备用。)
3-3. 验证
确认已保存的配置文件是否实际可用。
xcrun notarytool history --keychain-profile "focustimer-notarize"
若出现 Successfully received submission history. 的消息,则表示正常。其下的提交历史可能为空(因为尚未公证过任何内容,这是正常的),也可能有之前的记录。
关键陷阱 — Apple ID 与 GitHub 账户是不同的
这是首次配置直接分发时最容易卡住的地方。
- Apple Developer Program 账户 — 用于申请证书和公证(示例:
[email protected]) - GitHub 账户 — 第 3 篇中用于托管更新文件(示例:
[email protected])
两者通常使用不同的邮箱。特别注意:notarytool store-credentials 的 --apple-id 必须填写 Apple Developer 账户邮箱。若填写 GitHub 账户邮箱,认证会失败,而且错误信息不够友好,难以找到原因。
若两个账户的邮箱容易混淆,建议记录下哪个是 Apple 用、哪个是 GitHub 用。这一区别在本系列中会反复出现。
第 1 篇小结
跟到这里,你现在已经准备好以下内容:
- ✅ 发布自动化用命令行工具(
gh、create-dmg) - ✅ 活跃状态的 Apple Developer Program 会员资格
- ✅ 存储在钥匙串中的 Developer ID Application 证书
- ✅ 存储在钥匙串中的公证用凭据配置文件(
focustimer-notarize)
至此,签名和公证应用的准备工作已完成。但几乎没有应用只发布一次就结束。你需要不断推出修复 Bug、增加功能的新版本。如果是 App Store 应用,自动更新由 App Store 代劳;而直接分发则需要自行搭建这一机制。
下一篇将为 macOS 应用事实上的标准自动更新框架 Sparkle 创建 EdDSA 签名密钥。这是独立于证书之外、专门用于验证更新文件的机制。