修改SCPreferences持久化存储遇无效参数错误求助
解决SCPreferencesCommitChanges返回Code=1002 "Invalid argument"的问题
我之前也踩过类似的蓝牙plist修改坑,这个“设置值成功但提交失败”的矛盾错误,其实大概率是参数格式不规范或者权限/会话配置有问题,咱们一步步来排查:
1. 先修正AuthorizationFlags的重复问题
你代码里的flags重复写了.extendRights,虽然不一定是直接诱因,但规范的配置能避免潜在的权限异常:
let flags: AuthorizationFlags = [.interactionAllowed, .extendRights, .preAuthorize]
2. 更换SCPreferences会话的标识符
SCPreferencesCreateWithAuthorization的第二个参数是会话的唯一标识,你传的"defaults"太通用,系统可能会因为这个不规范的标识拒绝提交。建议换成你应用的Bundle ID,比如:
let preferences = SCPreferencesCreateWithAuthorization( kCFAllocatorDefault, "com.yourcompany.yourapp" as CFString, // 替换成你的真实Bundle ID "/Library/Preferences/com.apple.Bluetooth.plist" as CFString, authRef )
3. 重点检查PairedDevices的格式匹配
这是最常见的触发原因:你传入的paired对象的类型/结构和原plist里的PairedDevices不匹配。系统允许临时设置值,但提交时会严格验证plist合法性,一旦结构不对就会返回1002错误。
- 先读取原plist的
PairedDevices值,确认它的类型(通常是CFArray,内部是蓝牙设备的UUID字符串或字典) - 确保你构造的
paired对象和原结构完全一致,比如原先是数组就别传字典,元素类型也要严格对应
推荐先读取原值再修改,这样能保证结构绝对正确:
guard let prefs = preferences else { print("Failed to create preferences reference") return false } // 读取原PairedDevices值 if let originalPaired = SCPreferencesGetValue(prefs, "PairedDevices" as CFString) as? CFArray { // 在这里修改originalPaired得到新的数组(比如移除指定设备) let newPaired = ... // 你的修改逻辑 // 写入修改后的值 if SCPreferencesSetValue(prefs, "PairedDevices" as CFString, newPaired) { print("Set Value success") let ok = SCPreferencesCommitChanges(prefs) if ok { print("Commit success") } else { if let error = SCCopyLastError() { print("Commit Changes Error: \(error)") } } } else { if let error = SCCopyLastError() { print("Set Value Error: \(error)") } } } else { print("Failed to read original PairedDevices") }
4. 额外排查点:文件占用和权限
- 蓝牙守护进程
blued可能正在占用这个plist文件,导致无法提交。可以先断开所有蓝牙设备,或者重启blued(需要root权限:sudo launchctl stop com.apple.blued && sudo launchctl start com.apple.blued) - 确认权限获取是否成功:打印
AuthorizationCopyRights返回的osStatus,确保它等于errAuthorizationSuccess(即0):
print("Authorization status: \(osStatus)")
内容的提问来源于stack exchange,提问作者Mike JS Choi




