Xcode:不付费能否让 app 通过 macOS quarantine?
结论
不能。通过互联网分发 macOS app,并让它在新 Mac 上通过 Gatekeeper 的常规检查,通常需要完成以下步骤:
- 使用付费 Apple Developer Program 提供的
Developer ID Application证书签名; - 将 app 提交给 Apple 公证(notarization);
- 最好将公证票据 stapling 到 app;
- 打包并分发 app。
免费的 Personal Team 只能提供用于开发和本机测试的开发签名,无法取得 Developer ID Application 分发证书,也不能完成站外分发所需的标准公证流程。
严格来说,导致检查失败的并不是 quarantine 本身。quarantine 是下载文件携带的扩展属性。用户首次打开 app 时,Gatekeeper 会根据签名、公证票据和系统安全策略进行检查。没有经过 Developer ID 签名和公证的 app,仍可能被系统阻止,或需要用户手动确认后才能打开。
为什么 Personal Team 签名不够
Xcode 中的 Personal Team 通常使用类似下面的开发证书:
Apple Development: Name (TEAMID)
这种证书适用于开发阶段,包括:
- 从 Xcode 构建和运行 app;
- 在开发设备上调试;
- 为 bundle、嵌入的 framework 和 helper 建立一致的签名关系;
- 测试部分需要签名或 entitlement 的功能;
- 检查 app 签名后是否仍然完整。
它不是用于互联网公开分发的身份。站外分发通常需要:
Developer ID Application: Organization or Name (TEAMID)
因此,Automatically Manage Signing 只能自动管理当前账号有权使用的证书和 provisioning profile。它不能把 Personal Team 的开发签名转换成 Developer ID 签名,也不会自动让 app 获得公证资格。
正常的发布流程
加入 Apple Developer Program 后,可以在 Xcode 中使用 Developer ID 方式归档和导出,也可以通过命令行完成签名、公证和票据装订。
1. 使用 hardened runtime 签名
实际项目可能包含 framework、XPC service、helper tool 或其他嵌套代码。可以让 Xcode 处理签名,也可以自行按照从最内层组件到最外层 app 的顺序签名。
简化示例如下:
codesign \
--force \
--options runtime \
--timestamp \
--sign "Developer ID Application: Your Name (TEAMID)" \
"APPlayMIDI.app"
不要把 --deep 当成修复嵌套签名问题的通用办法。更稳妥的方式是分别正确签署每个嵌套组件,最后再签署最外层 app。
检查签名:
codesign --verify --deep --strict --verbose=2 "APPlayMIDI.app"
codesign -dvvv "APPlayMIDI.app"
2. 创建用于提交的 ZIP
使用 ditto 可以保留 macOS bundle 所需的元数据:
ditto -c -k --keepParent "APPlayMIDI.app" "APPlayMIDI.zip"
3. 配置公证凭据
建议将凭据保存在钥匙串中,避免把密码直接写入脚本:
xcrun notarytool store-credentials "notary-profile" \
--apple-id "name@example.com" \
--team-id "TEAMID" \
--password "APP_SPECIFIC_PASSWORD"
这里通常需要 Apple ID 的 app-specific password。认证方式可能随着 Apple 工具更新而变化,请以当前 Xcode 和 notarytool help 的说明为准。
4. 提交公证
xcrun notarytool submit "APPlayMIDI.zip" \
--keychain-profile "notary-profile" \
--wait
如果公证失败,可以获取日志:
xcrun notarytool log SUBMISSION_ID \
--keychain-profile "notary-profile"
5. 装订公证票据
公证成功后,对原始 app 执行:
xcrun stapler staple "APPlayMIDI.app"
xcrun stapler validate "APPlayMIDI.app"
完成后,再重新创建用于最终发布的 ZIP 或磁盘映像。如果在 stapling 前制作最终压缩包,包内的 app 将不包含已经装订的票据。
6. 检查 Gatekeeper 评估结果
spctl --assess --type execute --verbose=4 "APPlayMIDI.app"
这项检查可以作为参考,但无法完全代替在干净系统上测试真实的下载和首次启动流程。文件是否带有 quarantine 属性,也会影响实际行为。
不付费时可以怎样分发
不付费仍然可以发布源代码或未经公证的 binary,但无法获得与 Developer ID 签名、公证 app 相同的首次启动体验。用户可能需要通过 Finder 手动放行:
- 尝试打开 app;
- 打开“系统设置”中的“隐私与安全性”;
- 在相应提示处选择“仍要打开”。
在部分 macOS 版本中,用户也可以在 Finder 中按住 Control 点击 app,然后选择“打开”。具体界面和可用入口会因 macOS 版本及系统管理策略而异。
技术用户还可以使用:
xattr -dr com.apple.quarantine "APPlayMIDI.app"
但这不适合作为面向普通用户的正式安装方案。该命令会递归移除 quarantine 属性,相当于绕过原本应执行的首次安全检查。企业管理设备也可能禁止这种操作。
用户从源代码自行在 Xcode 中构建时,通常不会经历完全相同的“互联网下载文件”检查流程,因为构建产物未必带有 com.apple.quarantine 属性。但这并不意味着该 binary 已获得 Developer ID 签名或通过 Apple 公证。
免费签名是否还有实际用途
有,不过主要用于开发和测试,不能建立公开分发所需的信任链。
Personal Team 签名可以:
- 让 Xcode 正常部署和调试 app;
- 验证签名后的代码完整性;
- 为主程序和嵌套组件建立签名关系;
- 在允许的范围内测试 entitlements;
- 发现资源在签名后被修改等问题。
它不能:
- 取得
Developer ID Application身份; - 代替 Apple 公证;
- 保证从浏览器、邮件或聊天工具下载的 app 被 Gatekeeper 直接接受;
- 消除“未知开发者”或“无法验证开发者”之类的安全提示。
如果要向普通用户直接提供可下载的 macOS binary,付费开发者账号、Developer ID 签名和公证基本上是标准做法。如果只是共享源代码,供技术用户自行构建,Personal Team 仍然有用,但无法解决公开分发 binary 时的 Gatekeeper 检查问题。
备注:内容仅供参考。
