昨天终于心一横开了苹果开发者,一大早开了,想着我要一天搞定上架提交!然而,钱是付了,等到晚上九点多,才成功开通。好嘛,那第二天再努力吧,带着兴奋入睡,第二天一早起来开干。
事实是我把这想得太简单,出了舒适区,就真的想踏入泥沼一样寸步难行。搞了大半天才终于把不用上架的版本签好,晚上之前也把 pkg 打出来了。不容易啊!
下面讲讲一些值得注意的点吧。如果你也打算入坑 Tauri 开发,而且打算构建 macOS应用或者 iOS应用,记得收藏,以后会用到的。
证书
你先得搞清楚,CSR、CER、P12 这些概念分别是啥,不然肯定被 N 个证书搞得晕头转向。
在数字证书和公钥基础设施(PKI)领域,这三个缩写分别代表了证书申请、证书本身以及证书存储的不同阶段和格式。 简单来说,它们的关系可以看作是一个从申请到签发再到打包的过程。
CSR
本质:申请表
当你需要一个正式的 SSL/TLS 证书时,你首先要在服务器上生成一对密钥(私钥和公钥)。CSR 就是由你的公钥和一些身份信息(如域名、公司名称、国家等)组成的请求文件。
作用: 你把这个文件发给证书颁发机构(CA,如 Digicert, Let’s Encrypt)。
隐喻: 办护照时填写的“申请表”。表上有你的照片(公钥)和个人资料,但它还不是护照。
包含: 公钥 + 身份信息 + 数字签名。
CER
本质:正式证件
CA 收到你的 CSR 并核实身份后,会用他们的私钥对你的信息进行签名,生成一个证书文件,通常后缀是 .cer 或 .crt.
作用: 安装在服务器上,向客户端证明你的身份并提供公钥。
隐喻: 已经盖了章的正式“护照”。
包含: 你的公钥、CA 的签名、有效期、颁发者信息。它不包含私钥。
P12
本质:全家桶安装包
.p12 是一种二进制格式的容器,它可以把私钥、公钥(CER)以及中间证书链全部打包在一个文件里,并且通常由密码保护。
作用: 方便迁移。比如你想把证书从一台服务器搬到另一台服务器,直接导出一个 P12 文件即可。在 iOS 开发或 Java 服务中非常常见。
隐喻: 你的“保险箱”,里面装着护照(证书)、开启护照配套的钥匙(私钥)以及其他证明文件。
包含: 证书 + 私钥 + (可选) 证书链。
在解决了证书本质上区别之后,你还要搞清楚苹果自己的 N 种证书。Developer ID Application 用于不上架的分发,上架还要用到 Distribution 和 Mac Installer Distribution 两个证书。
机子里证书有两个,一个 Apple Development,一个 Developer ID Application,不小心把证书导错了一次,排查又卡住。
其次 Tauri 一定程度上有点黑盒,加上对苹果应用开发不熟悉,从 Tauri 那不算太完整的文档里逐步实现签名。而且关键是这些信息还散落在 macOS Application Bundle、macOS Code Signing、App Store 三个页面。
为了理清这三个页面的内容,又得把一堆苹果开发流程中的重要概念搞清楚。
概念
Entitlements
它是一组 key-value 对(权利字典),告诉操作系统“这个 App 允许使用哪些特殊能力”。例如:访问 iCloud、HomeKit、推送通知、相机、App Sandbox 等。这些权利会嵌入到 App 的二进制代码签名里。
iOS / macOS 上架时必须正确声明;Xcode 会自动生成 .entitlements 文件,签名时合并进去。
Notarization
Notarization 翻译过来就是做公证。你把已签名的 macOS App 上传给苹果,它会扫描恶意代码、检查签名问题。
扫描通过后,苹果给你的 App 发一个“公证票据”(ticket),你可以把它“钉”(staple)到 App 上。macOS Gatekeeper(门卫)看到有公证票据,就会放心让用户运行,而不会弹出应用损坏的错误。
使用 Developer ID 证书在 App Store 外分发的 macOS App 必须公证。
Provisioning Profile
一个由苹果服务器签名的 .mobileprovision / .provisionprofile 文件,里面包含:
App ID(Bundle ID)
开发者证书
授权的设备列表(开发阶段)
允许使用的 Entitlements 和服务
上架必须,非上架不需要。
双生配置
在搞清楚上面的概念之后就大概能明白了,Tauri 的构建配置必须分两种。
之前的一个卡点是,签名成功了也公证了,结果反而打不开,签名之前还能用 xattr -cr,现在用了都不行。
{
// ……
"macOS": {
"entitlements": "./entitlements.plist",
"signingIdentity": "Developer ID Application: XXX"
}
// ……
}
问了一轮 AI 以为是不知道什么原因导致的 entitlements 没写进去。但是后来又发现即使通过 codesign --force --deep --options runtime 手动把 entitlements 写进去了,依然打不开。
最后才恍然大悟,Tauri 文档上写的分开 tauri.appstore.conf 文件的必要性……
实际上打包非上架包的时候应该把 entitlements 删掉,这样反倒是打出来的包可以正常运行。
App Store 版本
然后发布 App Store 的版本我们外加一个配置文件 tauri.appstore.conf.json:
{
"bundle": {
"macOS": {
"entitlements": "./entitlements.plist",
"signingIdentity": "Apple Distribution: Dexter Chow (9J69XMW5FC)",
"files": {
"embedded.provisionprofile": "./provisioning/MindElixirMac.provisionprofile"
}
}
}
}
构建时运行:
pnpm tauri build --config src-tauri/tauri.appstore.conf.json --target universal-apple-darwin
App Store 版本不需要公正,跑公正只会提示你需要用 Developer ID Application 证书。因此我们需要把环境变量里公正用到的值清空,这样 Tauri 就不会自动公正了。
pnpm tauri build 之后拿到了 .app,接着还要用 pkgbuild 打包成 pkg.
这两步就用到了上面提到的两个证书:
Apple Distribution → 签 App 本身(。app)
Mac Installer Distribution → 签 安装包(。pkg)
最后使用 Transporter 上传 pkg 包(开了虚拟网卡 Transporter 传不了),注意打包兼容 Intel 芯片的 universal 包,如果不想兼容 Intel 芯片,系统要限定在 12.0 以上。
后话
我真的不敢想象没 AI 我看这些文档要看到何年何月。但是做好了,又觉得其实没那么难。所以确实,一件事做到过和没做到过就是完全不一样。没做到过你会怀疑每一个细节有问题,脑子炸炸的,做到了你就知道大致什么是没问题的。后续再处理问题就简单多了。

评论(0)