返回博客

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.plistkillall 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> 清除拒绝记录。

正解:macOS 13+ 统一用 com.apple.settings.*.extension 前缀

切到新 URL scheme 后,open "<新URL>" 可以在侧边栏完整的情况下精准导航到对应面板。验证方式:执行命令,观察系统设置侧边栏是否保持完整;或用 pluginkit -mAv | grep -i settings 确认所有面板扩展都在注册列表中。

一句话外卖

macOS 13 把系统设置重写了一遍,旧 com.apple.preference.* 深链接是定时炸弹——代码能编译、偶尔也能跑,但会把用户的侧边栏打爆,而且清缓存救不了;升级到 com.apple.settings.*.extension 格式,一劳永逸。