已签名公证的macOS .dmg安装时遭Gatekeeper拒绝的原因
已完成macOS应用(.dmg格式)的Developer ID签名与公证,且通过codesign验证签名有效,但在干净系统中安装/打开时仍触发Gatekeeper报错:“AppName无法打开,因为开发者未被验证”。
使用spctl检查出现两种矛盾结果:
- 执行
spctl --assess --type open --verbose=4 output/App.dmg返回:
output/App.dmg: rejected source=Insufficient Context
- 执行
spctl -a -t open --context context:primary-signature -v ./output/Unbounded-0.0.1-arm64.dmg返回:
./output/App.dmg: accepted source=Notarized Developer ID
应用通过electron builder完成签名与公证,同时单独对.dmg进行了签名和公证,问题仍未解决。
排查与修复步骤
1. 严格遵循签名公证流程顺序
必须先完成.app包的签名,再将.app打包为.dmg,最后对.dmg进行签名并提交公证,顺序颠倒会导致验证异常。
2. 检查Electron Builder配置完整性
在electron-builder.yml或package.json的打包配置中,确保开启Hardened Runtime并配置正确的权限文件:
mac: entitlements: ./entitlements.plist entitlementsInherit: ./entitlements.plist hardenedRuntime: true gatekeeperAssess: false # 禁用builder自带的Gatekeeper检查,避免冲突
entitlements.plist需包含必要的权限声明(示例):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.cs.allow-jit</key> <true/> <key>com.apple.security.cs.allow-unsigned-executable-memory</key> <true/> <key>com.apple.security.cs.disable-library-validation</key> <true/> </dict> </plist>
3. 重新附加公证凭证
公证完成后,务必将公证凭证绑定到DMG上,避免网络同步延迟导致Gatekeeper无法识别:
xcrun stapler staple output/App.dmg
验证绑定结果:
xcrun stapler validate output/App.dmg
需返回The validate action worked!才算成功。
4. 排查.app包的签名有效性
Insufficient Context错误通常源于内部.app包的问题,而非DMG本身:
- 检查.app签名详情:
codesign -dv --verbose=4 output/App.app
确认Authority链包含Developer ID Application: [你的开发者ID],且Hardened Runtime状态为enabled。
- 用spctl直接评估.app:
spctl --assess --type execute --verbose=4 output/App.app
需返回accepted且source=Notarized Developer ID。
5. 模拟真实用户场景测试
在干净系统中测试时,需通过Finder双击打开DMG,而非终端命令启动:
- 确保系统Gatekeeper设置为默认状态(
系统设置 > 隐私与安全性 > 允许从以下位置下载的App: App Store和已识别的开发者)。 - 若仍报错,右键点击.app文件选择「打开」,正常情况下系统会弹出允许打开的选项;若未出现该选项,说明签名公证仍存在问题。
6. 清理旧产物并重新打包
彻底删除旧的output目录,重新执行打包、签名、公证全流程,避免缓存文件干扰。
内容的提问来源于stack exchange,提问作者Chaudry Ali

