3、macOS平台部署:应用捆绑包(.app)结构、macdeployqt工具、代码签名与公证、DMG制作与分发
macOS 的部署,说实话,跟 Windows 和 Linux 完全是两码事。我第一次在 Mac 上打包 Qt 应用时,就被那个 .app 文件夹搞懵了——它看起来像个文件,双击却能运行,里面还藏着一整套目录结构。后来我才明白,这就是 macOS 的「应用捆绑包」机制。
嗯,咱们一步步来。先搞清楚 .app 里面到底长什么样,再谈怎么用工具自动搞定它。
3.1 应用捆绑包(.app)结构
macOS 的应用,本质上是一个文件夹。只不过系统给它穿了个马甲,让你看起来像个单一文件。你可以在 Finder 里右键点击任何 .app,选择「显示包内容」,就能看到它的真面目。
一个典型的 Qt 应用捆绑包结构是这样的:
MyApp.app/
├── Contents/
│ ├── Info.plist # 应用的元信息配置文件
│ ├── MacOS/
│ │ └── MyApp # 真正的可执行文件
│ ├── Resources/
│ │ ├── icon.icns # 应用图标
│ │ ├── MainMenu.nib # 界面资源(如果用了)
│ │ └── *.qm # 翻译文件
│ └── Frameworks/ # 依赖的框架(Qt 库等)
│ ├── QtCore.framework
│ ├── QtGui.framework
│ └── ...
这里面最关键的,是 Info.plist。它就像应用的身份证,告诉系统你的应用叫什么、用什么图标、支持哪些文件类型。我见过不少新手直接复制别人的 plist 文件,结果应用图标死活不显示——其实就是 CFBundleIconFile 字段写错了。
Info.plist 必填字段:
CFBundleName:应用显示名称CFBundleDisplayName:用户看到的名称CFBundleIdentifier:唯一标识符,比如 com.mycompany.myappCFBundleVersion:版本号CFBundleExecutable:可执行文件名CFBundleIconFile:图标文件名(不带 .icns 后缀)
我个人习惯把 Info.plist 放在项目的 resources/ 目录下,然后在 .pro 文件里用 QMAKE_INFO_PLIST 指定路径。这样每次编译都会自动复制进去,省心。
3.2 macdeployqt 工具
手动往 .app 里塞 Qt 框架?别傻了。Qt 官方提供了 macdeployqt,一条命令就能搞定依赖拷贝。
基本用法:
macdeployqt /path/to/MyApp.app -verbose=1
它会自动做三件事:
- 扫描可执行文件,找出所有依赖的 Qt 框架
- 把这些框架拷贝到
Contents/Frameworks/下 - 用
install_name_tool修改可执行文件的库搜索路径,让它们指向包内的框架
我曾经在项目里用了一个第三方库,macdeployqt 死活没把它打包进去。后来发现,那个库是用 dlopen 动态加载的,macdeployqt 扫描不到。解决办法是手动指定:
macdeployqt MyApp.app -executable=MyApp.app/Contents/MacOS/MyApp \
-libpath=/usr/local/lib
小技巧:如果你用了 QML,记得加 -qmldir=/path/to/qml 参数。否则 QML 插件和导入库不会被自动打包,应用在别的机器上会白屏。
还有一个坑:macdeployqt 默认不会处理 .dylib 文件。如果你自己编译了动态库,得手动把它们扔进 Frameworks/ 目录,或者用 -executable 参数逐个指定。
3.3 代码签名与公证
从 macOS 10.15 Catalina 开始,苹果强制要求所有应用必须经过「公证」(Notarization)才能正常运行。说白了,就是你的应用得先让苹果服务器扫描一遍,确认没病毒,然后用户才能打开。
签名和公证的流程,我总结成三步:
- 签名你的应用:用
codesign命令给 .app 打上你的开发者证书 - 提交公证:用
xcrun altool或notarytool把应用上传给苹果 - 绑定公证票据:把苹果返回的「通过」凭证嵌入到 .app 里
签名命令长这样:
codesign --deep --force --verify --verbose \
--sign "Developer ID Application: Your Name (TEAMID)" \
--options runtime \
MyApp.app
注意那个 --options runtime,这是硬性要求。不加的话,公证会失败。我当初就因为这个被拒了三次,气得想砸电脑。
公证提交(新版 notarytool):
xcrun notarytool submit MyApp.app \
--apple-id your@email.com \
--team-id TEAMID \
--password @keychain:AC_PASSWORD \
--wait
警告:公证需要联网,而且苹果的审核队列有时候很慢。我遇到过等 20 分钟才出结果的。建议在 CI/CD 流程里预留足够的时间。
公证通过后,别忘了绑定票据:
xcrun stapler staple MyApp.app
这一步是把苹果的「已公证」标记写入 .app,这样用户第一次打开时就不会弹警告了。
3.4 DMG 制作与分发
应用打包好了,怎么发给用户?macOS 上最通用的方式就是 DMG 镜像。它就像一个压缩包,但打开后会自动弹出窗口,用户把 .app 拖进 Applications 文件夹就行。
制作 DMG 我推荐用 create-dmg 这个开源工具。它比手动用 hdiutil 方便太多了:
create-dmg \
--volname "MyApp" \
--volicon "icon.icns" \
--background "background.png" \
--window-pos 200 120 \
--window-size 800 400 \
--icon-size 100 \
--icon "MyApp.app" 200 190 \
--hide-extension "MyApp.app" \
--app-drop-link 600 185 \
"MyApp-1.0.dmg" \
"MyApp.app"
参数解释一下:
--volname:DMG 挂载后的卷标名--background:背景图,建议 800x400 像素--icon:指定 .app 图标在窗口里的位置--app-drop-link:那个指向 Applications 文件夹的快捷箭头位置
我个人习惯在 DMG 里放一个 README.txt,写上版本号和更新日志。用户打开 DMG 就能看到,不用额外打开网页。
DMG 制作要点:
- DMG 本身也要签名和公证!否则用户下载后可能打不开
- 背景图不要用太复杂的图案,简洁为主
- 窗口大小和图标位置要提前算好,别让图标叠在一起
- 建议用
--no-internet-enable参数,避免 DMG 联网检查
最后,别忘了给 DMG 签名:
codesign --sign "Developer ID Application: Your Name (TEAMID)" \
MyApp-1.0.dmg
然后再公证一次。嗯,你没看错,DMG 也要公证。苹果就是这么「严谨」。
知识体系总览
下面这张图,是我自己总结的 macOS 部署全流程。你可以把它当成 checklist,每次打包时对照着走一遍:
说实话,macOS 的部署流程比 Windows 复杂不少。但只要你把签名和公证的脚本写好了,后面就是一条命令的事。我个人习惯把这整套流程写成一个 deploy_mac.sh 脚本,放在项目根目录下。每次发版时跑一遍,省时省力。
嗯,关于 macOS 部署,核心就是这些。记住:.app 结构要完整,依赖要打包干净,签名和公证不能跳过,DMG 要做得漂亮。做到这四点,你的 Qt 应用在 Mac 上就能跑得稳稳当当。