OpenLogi macOS 打包内幕:签名、公证、DMG 与 dev/production 双通道 Bundle 全解指南
【免费下载链接】OpenLogi⚡️A native, local-first alternative to Logitech Options+, written in Rust 🦀 — remap buttons, DPI, and SmartShift over HID++. No account, no telemetry.项目地址: https://gitcode.com/GitHub_Trending/op/OpenLogi
OpenLogi 是一款用 Rust 编写的本地优先 Logitech Options+ 替代品,无需账号、无遥测,通过 HID++ 协议重映射按钮、DPI 与 SmartShift。它的 macOS 版本要交付签名 + 公证的.dmg,本文带你拆解这套打包流水线:签名、公证、DMG 制作,以及 dev/production 双通道 Bundle 的身份隔离机制。
为什么 macOS 打包比想象中难:先看懂 3 个关键词
在动手之前,先建立三个概念,后面所有设计都围绕它们展开:
| 关键词 | 含义 | 在 OpenLogi 中的对应 |
|---|---|---|
| 代码签名 | 用 Apple 身份对每个可执行文件签名,macOS 据此识别"谁在运行" | Agent 的辅助功能(TCC)授权绑定签名身份 |
| 公证 | 苹果对分发包的最终审查,签名 + 安全时间戳是前提 | Developer ID 签名 +--timestamp |
| TCC | 系统隐私授权(辅助功能、输入监控、摄像头)按 Bundle 身份记名 | 身份一变,授权全部作废 |
最后一点是理解双通道设计的钥匙:macOS 把权限授权记在 Bundle 的CFBundleIdentifier上,身份换了 = 授权作废 + 配置目录漂移。
打包流水线总览:5 条 xtask 命令搞定 Bundle
所有 macOS 打包逻辑集中在 xtask/src/commands/macos.rs 中,共 5 个子命令:
macos icon—— 从 Icon Composer 文档编译应用图标macos bundle—— 构建OpenLogi.app,默认 dev 通道macos dev-bundle—— 由 cargo runner 驱动,把cargo run的二进制包成target/dev/OpenLogi.appmacos dmg—— 从现成 Bundle 制作品牌化 DMGmacos package——一键发行:production 通道构建 Bundle → 可选 Developer ID 签名 → 打包签名 DMG
其中macos bundle的核心流程(见 xtask/src/commands/macos/bundle.rs)是:
编译图标 → 构建全部 Release 二进制 →
cargo-bundle生成.app→ 嵌入 Agent/Overlay 助手 → 嵌入 CLI → 校验二进制齐全 → 盖章身份 → 校验身份 →最后才签名(因为签名会封死Info.plist)
一个 Bundle 里其实装了4 个可执行文件:GUI(openlogi-desktop)、常驻 Agent(openlogi-agent)、Actions Ring 悬浮窗 Overlay(openlogi-overlay)和命令行 CLI。助手表定义在 xtask/src/commands/macos/bundle/embed.rs。
dev 与 production 双通道 Bundle:身份隔离是怎么做的
OpenLogi 用一个Channel枚举管理两套身份(xtask/src/commands/macos/bundle/identity.rs)。每个组件在两个通道下的身份如下:
| 组件 | production 身份 | dev 身份 |
|---|---|---|
| App | org.openlogi.openlogi/ OpenLogi | org.openlogi.openlogi-dev/ OpenLogi Dev |
| Agent | org.openlogi.agent/ OpenLogi Agent | org.openlogi.agent-dev/ OpenLogi Agent Dev |
| Overlay | org.openlogi.overlay/ OpenLogi Overlay | org.openlogi.overlay-dev/ OpenLogi Overlay Dev |
品牌常量统一收敛在 crates/openlogi-core/src/brand.rs,dev 通道 = 正式 ID 加-dev后缀、名称加Dev后缀。
为什么不能偷懒?这段注释里藏着一段血泪史:releases 0.6.24–0.6.26 曾把 dev 身份的包发给了用户,直接作废了所有已授予的权限,配置也读错了目录。所以 OpenLogi 规定身份从不推断,而是显式盖章:
stamp()—— 把所选通道身份写进每个组件的Info.plistverify()—— 签之前逐项读回校验,dev 包绝不可能被误发布verify_icons()—— 确保每个组件都带 OpenLogi 图标,隐私面板不会显示空白行
嵌套助手的目录名与显示名严格一致(如Contents/Library/LoginItems/OpenLogi Agent.app),因为 macOS 隐私面板在元数据过期时会回退用文件名显示——名字差一个字母,用户就无法辨认该行属于谁。
从内到外签名:为什么放弃 --deep,改用 4 步签名顺序
签名实现位于 xtask/src/commands/macos/bundle/signing.rs,顺序是由内向外:
- Agent 助手(独立签名)
- Overlay 助手(独立签名)
- 内嵌 CLI(
Contents/MacOS/openlogi,带摄像头权限) - 外层 App(封装上面所有已签名内容)
之后用codesign --verify --strict逐一复核 4 个目标。
这里有两个关键取舍:
- 不用
--deep:它已被苹果弃用,且无法给嵌套助手独立签名。而 Agent 的辅助功能授权恰恰需要一份跨更新保持稳定的独立签名身份,否则每次升级用户都要重新授权。 - 加固运行时 + 时间戳:所有签名都带
--options runtime。production 用--timestamp(安全时间戳,是公证的必要条件);本地开发签名用--timestamp=none,只保证本机可运行。
本地签名走一条降级链(signing.rs):OPENLOGI_SIGN_IDENTITY→OPENLOGI_LOCAL_CODESIGN_IDENTITY→ 自动发现首个Apple Development:身份 → 都没有就跳过并警告(未签名包每次构建会被 ad-hoc 重签,辅助功能授权会反复失效)。
摄像头是另一个细节:GUI 和 CLI 会打开摄像头(预览/快照),需要单独的加固运行时例外,声明在 crates/openlogi-desktop/bundle/OpenLogi.entitlements 中;Agent 和 Overlay 不用摄像头,刻意不带这个权限。
公证(Notarization)前的最后一道验证
公证是苹果对分发包的最终审查,仓库把公证所需的全部前提内置在构建流程里:Developer ID 签名 + 加固运行时 + 安全时间戳 + 逐组件独立签名。production 通道只有在提供签名身份时才会真正签名(bundle.rs),未提供时明确打印 "unsigned" 提示,从源头杜绝"把未签名包当发行物"的可能。
DMG 环节还有一道身份闸门:只要指定了签名身份,就强制校验包内 Bundle 是 production 身份(xtask/src/commands/macos/dmg.rs)——一个 dev 包若流入用户手中,会作废其权限授权并切换配置目录,这与 0.6.24–0.6.26 的教训如出一辙。
品牌化 DMG 制作步骤:760×480 背景与 ULMO 压缩
DMG 由create-dmg驱动,细节都经过精打细算:
- 格式选 ULMO(LZMA):比默认 UDZO(zlib)小约 20%,且 macOS 10.15+ 均可挂载,低于项目 13.0 的底线
- 几何锁定:背景图是 760×480 的品牌图,
create-dmg使用外窗口尺寸,故窗口高 = 480 + 32pt Finder 标题栏 = 512;图标 128px,应用图标定位 (212, 250),"拖到 Applications" 链接定位 (548, 250) - 背景图按需下载:品牌背景通过
OPENLOGI_DMG_BACKGROUND_URL指定,默认从官方资源端拉取 - DMG 本体也签名:
codesign --force --timestamp --sign后附--verify复核
dev bundle 快速上手:cargo run 也能跑完整应用
cargo run -p openlogi-desktop跑出来的裸target/debug二进制没有Info.plist和资源——macOS 只会显示通用图标、不注册openlogi://深链、TCC 也无从记名。macos dev-bundle就是为了解决这一切(xtask/src/commands/macos/dev_bundle.rs):
- 与发行包共用同一套代码:同一张身份表、同一份助手表、同一组
Info.plist模板(desktop-dev/Info.plist),历史上两套实现曾导致 dev 版 Overlay 丢图标、dev 身份被迫改名两次 - 硬链接加速:95MB 的二进制优先硬链接进 Bundle(瞬时完成);签名时因
codesign原地改写 Mach-O 而改用拷贝,避免"背着 Cargo 改了自己的构建产物" - Profile 匹配:助手与 GUI 同 profile 构建——release GUI 配 debug Agent 是调试噩梦
- LaunchServices 注册:
lsregister -R让openlogi://深链指向 dev 构建,且能重新抢占已安装版本占用的 scheme OPENLOGI_DEV_AGENT=0可跳过助手嵌入,只打主程序
常用命令速查表 ⚡
| 场景 | 命令 |
|---|---|
| 本地构建(dev 通道,默认) | cargo xtask macos bundle |
| 显式 production 通道构建 | cargo xtask macos bundle --channel production |
| 一键发行(签名 + DMG) | OPENLOGI_SIGN_IDENTITY="Developer ID Application: …" cargo xtask macos package |
| 交叉打包 Intel 版 | cargo xtask macos package --target x86_64-apple-darwin |
| 离线打包设备资产 | OPENLOGI_BUNDLE_ASSETS=1 cargo xtask macos bundle |
| 重新编译应用图标 | cargo xtask macos icon |
更多打包背景可查阅 xtask/README.md 与 docs/DEVELOPMENT.md。
关键文件清单 📁
- xtask/src/commands/macos/bundle/identity.rs —— 双通道身份设计说明
- xtask/src/commands/macos/bundle/signing.rs —— 从内到外签名与本地签名降级链
- xtask/src/commands/macos/dmg.rs —— 品牌化 DMG 几何与压缩策略
- crates/openlogi-core/src/brand.rs —— 三个 Bundle ID 与
-dev后缀的唯一事实源 - crates/openlogi-desktop/bundle/ —— Agent/Overlay 的
Info.plist模板与摄像头 entitlements
总结:OpenLogi 的 macOS 打包把"身份"当成一等公民——显式盖章、逐项校验、由内向外签名,用双通道隔离开发环境与发行环境,最终产出一个经得起公证、授权跨更新持久的分发包。这套思路对任何需要辅助功能权限的 macOS 工具都是很好的参考范本。
【免费下载链接】OpenLogi⚡️A native, local-first alternative to Logitech Options+, written in Rust 🦀 — remap buttons, DPI, and SmartShift over HID++. No account, no telemetry.项目地址: https://gitcode.com/GitHub_Trending/op/OpenLogi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考