macos 应用需严格按签名→公证→装订闭环流程落地:签名须启用 hardened runtime 并配 entitlements;公证必须用 notarytool 提交合规包体;装订票证后经 spctl 验证为 accepted 才真正可信。
要让 macos 应用真正被系统信任、用户零阻碍打开,签名(codesign)和公证(notarization)不是“做了就行”,而是必须按顺序、带配置、闭环落地的完整流程。关键不在多一步,而在每一步都精准到位。
签名必须启用 hardened runtime 并配对 entitlements
仅用 Developer ID Application 证书签名远远不够。从 macOS 10.14.5 起,Gatekeeper 强制要求应用启用 hardened runtime(硬化运行时),否则即使签名有效,也会在首次运行时触发“无法验证开发者”警告。
- 签名命令中必须包含 --options=runtime 参数,例如:
codesign -s "Developer ID Application: XXX" --deep --timestamp --options=runtime --entitlements MyApp.entitlements MyApp.app - entitlements 文件需显式声明所需权限,如
com.apple.security.get-task-allow(调试必需)、com.apple.security.files.user-selected.read-write(文件访问)等,缺失会导致签名通过但运行崩溃 - 所有嵌套内容(如 Electron 的 .asar、Python 的 .so 文件、自定义 framework)都需单独签名,否则
codesign -v MyApp.app会报 “a sealed resource is missing or invalid”
公证必须用 notarytool,且提交前确认包结构合规
苹果已于 2023 年 11 月全面停用 altool,强制使用 notarytool。但工具切换只是表象,真正卡住公证的往往是包体本身不符合 Apple 的扫描规则。
- 提交前务必压缩为 .zip 或 .dmg(UDIF 格式),不能直接提交 .app;.pkg 安装包需确保 bundle identifier 唯一且与证书匹配
- 禁止包含脚本解释器(如 /usr/bin/python)、硬编码路径(/tmp/xxx)、未签名的第三方二进制(尤其是 FFmpeg、ffmpeg-bin 等常见组件)
- 使用
xcrun notarytool submit MyApp.zip --keychain-profile "MyProfile" --wait提交后,等待返回 “Accepted” 状态,而非仅看上传成功
公证票证必须 stapled 到应用包内
公证成功 ≠ 用户能顺利打开。Apple 服务器生成的票证(ticket)默认只发布在线,用户首次运行时需联网校验——一旦网络异常或 Apple 服务短暂不可用,就会弹出“无法检查是否含恶意软件”并阻拦启动。
- 公证通过后,立即执行装订:
xcrun stapler staple MyApp.app(对 .app)或xcrun stapler staple MyApp.dmg(对磁盘映像) - 装订后验证是否生效:
spctl --assess --type execute MyApp.app应无输出;若有提示,说明 stapler 失败或路径错误 - 装订是分发前最后一步,必须集成进 CI/CD 流程,不能依赖人工补做
持续验证签名与公证状态的自动化手段
开发和交付过程中,靠肉眼确认“应该没问题”极易遗漏。建议每次构建后自动运行三道检查:
-
本地签名完整性:运行
codesign --verify --verbose MyApp.app,确认输出含 “signed Bundle with Mach-O thin (x86_64)” 且无 error -
票证嵌入有效性:运行
stapler validate MyApp.app,返回 “The staple and validate action worked!” 才算真正闭环 -
Gatekeeper 综合评估:运行
spctl --assess --type execute --verbose=4 MyApp.app,结果为 “accepted” 表示全部通过
不复杂但容易忽略装订这一步。











