macOS 13+ 系统设置侧边栏只剩「通用」——旧版深链接的定时炸弹
给桌面应用接权限引导时,「点这里去系统设置开屏幕录制」这种按钮几乎是标配。我在一个 Tauri 应用里随手沿用了 macOS 12 时代的老 URL scheme,本地测试没问题,上了用户那边却一下子把系统设置搞废了——侧边栏 30 多个条目全消失,只剩一个孤零零的「通用」。更诡异的是:退出 App 再进、删缓存、杀 cfprefsd,全部无效,看起来像文件级别的深度损坏。
现象
调用下面这行代码后:
std::process::Command::new("open")
.arg("x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture")
.spawn();用户的「系统设置」侧边栏立刻退化——只留下「通用(General)」,外加偶发的某个第三方扩展(比如 MySQL.prefPane)。所有隐私、网络、蓝牙、通知等入口全部消失。退出重开、清 ~/Library/Saved Application State、清 ~/Library/Preferences/com.apple.systempreferences.plist、killall cfprefsd——挨个试,挨个无效。
根因
macOS 13(Ventura)把「系统偏好设置」彻底重写成了「系统设置」,底层改用 ExtensionKit + XPC 管理各个面板。侧边栏的枚举工作由 pluginkit daemon 和 Settings XPC 在系统级完成,不是进程内的用户态逻辑。
旧版 com.apple.preference.* URL scheme 是为 macOS 12 及以前的「System Preferences」设计的。在 macOS 13+ 上,系统会用一个兼容 shim 尝试解析旧 URL,但这个 shim 有时会把 daemon 的面板枚举状态搞乱,导致侧边栏只呈现出「降级兼容状态」里仅有的 General 条目。
受影响的状态存活在 pluginkit / Settings XPC daemon 里,这是系统级进程,不受用户空间的 plist 删除或 killall cfprefsd 影响。你在用户目录下删再多缓存都没用——损坏的状态在更底层。
另外,那个孤独的第三方 prefPane(MySQL、某驱动等)是幸存者效应,不是罪魁祸首。它在兼容模式下恰好被枚举进来了,删掉它同样无法恢复正常侧边栏(已验证)。
正解
1. 换用 macOS 13+ 新 URL scheme
新的系统设置面板以 ExtensionKit bundle 为单位,URL 格式完全不同:
| 目标 | macOS 13+ 正确 URL |
|------|-------------------|
| 屏幕录制 | x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_ScreenCapture |
| 麦克风 | ...?Privacy_Microphone |
| 摄像头 | ...?Privacy_Camera |
| 辅助功能 | ...?Privacy_Accessibility |
| 完全磁盘访问 | ...?Privacy_AllFiles |
// Tauri — macOS 13+ 正确写法
std::process::Command::new("open")
.arg("x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_ScreenCapture")
.spawn();2. 已经崩了的侧边栏——只能重启
这不是退而求其次,是唯一有效路径:重启 Mac。重启会把 pluginkit / Settings XPC daemon 从头初始化,侧边栏恢复正常。告知用户时不用遮遮掩掩,就说「这是 macOS 系统级的状态重置,重启可以修好」。
3. 权限引导优先用系统对话框,而非跳转设置
对于首次授权场景,更好的做法是调系统 API 触发原生权限弹窗,避免完全依赖深链接:
// 查询状态(不触发弹窗)
CGPreflightScreenCaptureAccess()
// 首次请求(触发系统弹窗)
CGRequestScreenCaptureAccess()只有当用户已经拒绝过(系统不再弹窗)时,才 fallback 到 Settings 深链接——并且用新版 URL。如果想让系统重新弹授权框,可用 tccutil reset ScreenCapture <bundle-id> 清除拒绝记录。
切到新 URL scheme 后,open "<新URL>" 可以在侧边栏完整的情况下精准导航到对应面板。验证方式:执行命令,观察系统设置侧边栏是否保持完整;或用 pluginkit -mAv | grep -i settings 确认所有面板扩展都在注册列表中。
一句话外卖
macOS 13 把系统设置重写了一遍,旧
com.apple.preference.*深链接是定时炸弹——代码能编译、偶尔也能跑,但会把用户的侧边栏打爆,而且清缓存救不了;升级到com.apple.settings.*.extension格式,一劳永逸。