在AI时代最稀缺的不是代码,而是“创意”。
那么我们怎么把“灵光一闪”变成一个个真正的产品,甚至发布上线和运营呢?

大家好,这是《用AI做点真东西》系列文章之一。作为一个工作十几年,「0编码经验」开始AI Coding的产品经理,希望我的视角,能给有相同经历的你带来一些帮助和启发!
背景:为什么会遇到APP分发失败?
其实我已经使用AI Coding一段时间,并有点成果。其中就有一款支持HTML/MD文档管理的本地编辑器。这是基于我对AI生成文档编辑和管理的朴素需求开始,而后每天使用迭代了几十个版本的产物。
【AI Agent实战】我是如何用superpowers开发出HTML编辑器的?1个小白可以持续迭代的方法
然而,在我觉得时机相对成熟,想要更大规模分享给朋友使用的时候,一个问题拦在了我面前——“苹果电脑用户打包后,双击 App 会出现“无法验证开发者”?”(文章较长,建议收藏需要的时候可详细对照)。

先说结论:App在苹果设备分发需要证书和验证
我的目标是把 DMG 放到自己的网站、GitHub Releases、或发送给朋友安装使用,不需要把 App 上架到 Mac App Store。
但是,仍然需要:
Apple Developer Program 会员资格 Developer ID Application 证书 Hardened Runtime(硬化运行时) Apple Notary Service 公证 最终的 Gatekeeper 验证
App Store 分发是另一套流程,使用的是 Mac App Distribution 证书和 App Store Connect。本文只讨论“自由分发 DMG”。
整体流程如下:

第一步:注册 Apple Developer Program

打开 Apple Developer Program,使用你的 Apple ID 注册并加入 Apple Developer Program。
个人开发者通常需要支付每年 99 美元的会员费用,具体金额可能会根据地区和税费显示不同。缴费成功并通过审核后,你会收到 Apple 的确认邮件。
个人账号就可以完成本文的流程,不需要注册公司账号。
第二步:创建 Developer ID Application 证书
1. 生成 CSR
打开“钥匙串访问”,注意菜单在 Mac 屏幕最顶部,不在应用窗口内:
钥匙串访问 → 证书助理 → 从证书颁发机构请求证书
填写:
保存生成的.certSigningRequest文件。此时私钥会自动生成在“登录”钥匙串中。Apple 官方 CSR 步骤

2. 创建证书
证书解决的是“这个 App 是谁签名的”。

在 Certificates, Identifiers & Profiles 中:
点击右上角的“+” 选择 Developer ID Application 选择现代的 G2 Sub-CA 上传 CSR 文件 点击 Continue 下载 .cer 文件 双击 .cer,安装到“登录”钥匙串
不要把 Developer ID Application 和 Developer ID Installer 混在一起。本文分发的是 App 和 DMG,应该使用 Application 证书。

这里有一个坑:证书需要安装到钥匙串的“登录”目录下,如果你此时在钥匙串访问里侧边选项是“系统根证书”,则双击会报错。

点击“登录”,安装成功。

最终在“钥匙串访问 → 登录 → 我的证书”中确认:证书左边可以展开,并且下面有对应私钥。
终端检查:
security find-identity -v -p codesigning你应该看到类似:
Developer ID Application: Your Name (TEAM_ID)
如果只看到证书,展开后没有私钥,说明证书和 CSR 不是同一对,需要重新生成。

第三步:配置苹果公证凭据
公证服务需要验证你的 Apple 账号。
创建 App 专用密码
打开 Apple Account,进入:
登录与安全 → App 专用密码 → 生成 App 专用密码这串密码不是 Apple ID 主密码,也不是 Mac 登录密码。
生成 App 专用密码需要账户已开启双重认证。Apple 官方说明



将公证密码保存到钥匙串
把下面的占位符替换成自己的信息:
xcrun notarytool store-credentials "HTMLStudio-notary" \ --apple-id "<APPLE_ID>" \ --team-id "<TEAM_ID>"命令提示输入密码时,粘贴刚才生成的 App 专用密码。
第四步:验证公证凭据
xcrun notarytool history \ --keychain-profile "HTMLStudio-notary"
第五步:构建并签名 App
进入项目目录:
cd "/path/to/html-doc-center"设置本次构建变量:
SIGNING_IDENTITY="Developer ID Application: Your Name (TEAM_ID)"VERSION="$(tr -d '[:space:]' < VERSION)"APP="dist/HTMLStudio.app"DMG="dist/HTMLStudio-$VERSION-macos-arm64.dmg"先删除旧产物:
rm -rf build dist HTMLStudio.spec安装构建依赖:
python3 -m pip install -r requirements-build.txt
构建 App,并让 PyInstaller 签名内部框架、动态库和可执行文件:
python3 build.py \ --version "$VERSION" \ --codesign-identity "$SIGNING_IDENTITY"签名前清除无关扩展属性:
xattr -cr "$APP"对外层 App 开启 Hardened Runtime 并加时间戳:
codesign --force \ --timestamp \ --options runtime \ --entitlements packaging/macos/entitlements.plist \ --sign "$SIGNING_IDENTITY" \ "$APP"严格验证:
codesign --verify \ --deep \ --strict \ --verbose=2 \ "$APP"成功时应该看到:
valid on disksatisfies its Designated Requirement
检查 Apple Silicon 架构:
lipo -archs "$APP/Contents/MacOS/HTMLStudio"应该输出:
arm64从这一步开始,不要再向 App 包内部写入配置、日志或其他文件。
第六步:创建并签名 DMG
先准备 DMG 展示目录:
rm -rf build/dmg-rootmkdir -p build/dmg-rootditto "$APP" "build/dmg-root/HTMLStudio.app"ln -s /Applications "build/dmg-root/Applications"创建 DMG:
hdiutil create \ -volname "HTML Studio" \ -srcfolder "build/dmg-root" \ -format UDZO \ -ov \ "$DMG"对最终 DMG 单独签名:
codesign --force \ --timestamp \ --sign "$SIGNING_IDENTITY" \ "$DMG"
验证 DMG:
codesign --verify --verbose=4 "$DMG"hdiutil verify "$DMG"
记录公证前哈希:
shasum -a 256 "$DMG"
这一步之后不要重新生成、重新签名或修改 DMG。签名后改内容,会导致 codesign 或公证失败。
第七步:使用 notarytool 提交公证
提交时只提交一次:
xcrun notarytool submit "$DMG" \ --keychain-profile "HTMLStudio-notary" \ --wait记下 Apple 返回的提交 ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
如果本地等待时间太长,可以按 Control + C 结束本地等待,但不要再次提交同一个 DMG。服务器上的任务会继续处理。
查询状态:
xcrun notarytool info "<SUBMISSION_ID>" \ --keychain-profile "HTMLStudio-notary"Accepted
下载公证日志。即使 Accepted,也建议检查日志中的 warning:
xcrun notarytool log "<SUBMISSION_ID>" \ --keychain-profile "HTMLStudio-notary" \ "notarization-log.json"Invalid
打开 notarization-log.json 查看具体错误。修复后必须从“清理旧产物”开始重新构建、签名和提交,不要在原 DMG 上直接补签。
In Progress
继续使用 notarytool info 查询。不要重复提交第三份、第四份 DMG。
最终可以看到如下结果:

第八步:Staple 公证票据
只有状态为 Accepted 才执行:
xcrun stapler staple -v "$DMG"xcrun stapler validate -v "$DMG"注意:staple 会修改 DMG,所以 stapling 后的哈希和提交前哈希不同是正常现象。

第九步:Gatekeeper 最终验证
执行完整验证:
codesign --verify --verbose=4 "$DMG"hdiutil verify "$DMG"spctl --assess \ --type open \ --context context:primary-signature \ --verbose=4 \ "$DMG"成功时通常会看到:
acceptedsource=Notarized Developer ID
最终可自由分发的文件是:
dist/HTMLStudio-2.6.0-macos-arm64.dmg你可以把它放到 GitHub Releases、自己的网站、网盘或公司内网,不需要上传 Mac App Store。
常见问题
“输入登录钥匙串密码”是什么?
这是当前 Mac 用户的登录密码,不是 Apple ID 密码,也不是 App 专用密码。
为什么签名验证失败?
最常见原因是签名完成后,流程又改写了 Contents/Resources、日志、配置或隐藏文件。修复方式是清理 build 和 dist,重新构建,并严格按照“签名 App → 创建 DMG → 签名 DMG → 公证”的顺序执行。
为什么长时间 In Progress?
先用提交 ID 查询状态。不要重复提交。新账号、首次公证或 Apple 后台队列都可能增加等待时间;如果持续异常,查看 Apple Developer 系统状态 并联系 Apple Developer Support。
最终检查清单
[ ] Apple Developer Program 已注册并通过审核 [ ] Developer ID Application 证书与私钥已配对 [ ] App 开启 Hardened Runtime [ ] App 签名验证通过 [ ] DMG 创建后单独签名 [ ] DMG 公证状态为 Accepted [ ] stapler validate 通过 [ ] codesign、hdiutil、spctl 全部通过 [ ] 只分发最终的 DMG,不分发 unnotarized 文件
夜雨聆风