决定要做之后,第一件事不是写代码,而是回答两个问题:现成的项目到底怎么样,以及我需要的能力在这台机器上还能不能用。

第二个问题尤其关键。让一个后台 App 在 Touch Bar 上常驻显示,公开的 API 做不到,只能用 Apple 的私有接口。私有接口随时可能被系统更新拿掉,所以必须先在自己的机器上验证,而不是想当然。

现有项目:没有一个能放心推荐

只做“Touch Bar 上显示 Dock、点击切换”的项目有几个。TouchSwitcher 最接近,但它闭源,而且要先点一下入口才显示,并不常驻;MTMR 开源,配置里有 dock 类型,但很久没有更新;EnergyBar 是 Objective-C 写的,同样多年没有更新;还有几个是 Pock 的 fork。Pock 和 PockV2 功能最全,是插件化架构,也正是我用下来不稳定的那个。

结论是:没有能放心推荐的现成方案,值得自己做一个。

它们为什么不稳定

搞清楚这一点,就知道自己做的时候要避开什么。第一,公开 API 做不到:NSTouchBar 只在自己的 App 位于前台时才显示,后台常驻只能调私有接口。第二,系统会把自定义的 Touch Bar 收回去:睡眠唤醒、锁屏解锁、系统的 Touch Bar 进程重启之后都会发生,没处理全,表现就是“用着用着消失了”。

第三,切换 App 会被系统拦:macOS 14 起激活规则改成协作式,后台进程发起的激活可能被忽略,表现就是“点了没反应”。第四,架构负担:插件化、小组件多,每次系统更新都容易出兼容问题。

在本机验证私有接口

我先写了一个探针,在本机逐个检查需要的接口:显示一条 Touch Bar、撤下、在控制条里放一个入口按钮、让入口常驻、隐藏左侧的关闭按钮。这几项都在。同时也发现,旧的方法名 presentSystemModalFunctionBar 已经被系统移除了,只调用这个名字的项目会直接失效,这正是这类工具会突然“坏掉”的一个真实例子。

然后我用一个最小的程序真的往 Touch Bar 上放了一个按钮,并用 screencapture -b 这条能截取 Touch Bar 的命令确认。结果是:把 placement 设为 1(占满整条)能正常显示;设为 0 时,在“展开的控制条”这个显示模式下完全不显示,而 isVisible 却仍然返回 true。这个“状态说谎”的发现,直接决定了后面不能靠 isVisible 去判断 Touch Bar 有没有真的显示出来。

分发:App Store 不行,DMG 可以

私有接口过不了 App Store 审核,而且沙盒里读不到 Dock 的配置,所以 Mac App Store 这条路是断的。App Store 之外可以正常分发:用 Developer ID 证书签名并公证之后,别人下载双击就能打开,Pock 和 MTMR 也都是这样发的。这个结论一开始就定下来,后面就不会在“要不要上架”上反复。

探针留了下来

这个探针后来没有丢掉,整理成了项目里的诊断工具:每次 macOS 大版本更新之后先跑一次,它会列出用到的每一个私有接口还在不在,还会顺带打印 Touch Bar 显示模式、台前调度这些会影响行为的设置。哪一项变成了缺失,对应的功能就会在 App 里自动关闭,而不是崩溃。

还有一个细节:收起 Touch Bar 之后,它会回到系统控制条,这时 isVisible 变成 false;而在“展开的控制条”模式下,控制条里看不到我们放的入口按钮。这也是早期版本里做过一个“收起十秒后自动恢复”按钮的原因,后来它被去掉了,改成从菜单开关。

小结:可行,并且有一个必须记住的坑

可行性验证的结论是三句话:技术上可行;有一个必须记住的坑,isVisible 不可信;分发走 DMG。这一步很短,但避免了最糟的情况:写了一大堆代码,最后才发现关键接口在这个系统上根本不存在。