macOS沙盒应用访问外部资源需走授权+凭证双流程:用户通过NSOpenPanel显式选择路径后调用startAccessingSecurityScopedResource(),操作完立即stopAccessing,持久化需保存bookmarkData并配置对应entitlements和Info.plist字段。

macOS 沙盒应用调用外部资源,不是“能不能”的问题,而是“怎么合法走通”的问题——系统从内核层就切断了默认路径访问,所有越界操作都会被拦截并返回 Operation not permitted,这不是权限没配对,而是沙盒策略主动拒绝。
沙盒默认只认三类路径
应用启动后,天然能读写的只有:
- 自身容器目录:
~/Library/Containers/<bundle-id>/Data/(含 Documents、Caches、Application Support 等子目录) - 临时目录:
~/Library/Containers/<bundle-id>/Data/tmp/ - 用户通过
NSOpenPanel或NSSavePanel显式选中的单个文件或文件夹(仅本次会话有效,需额外处理才能持久)
访问外部资源必须走“授权+凭证”双流程
想读写 ~/Documents、外接磁盘、iCloud Drive 或 OneDrive 中的文件,不能硬编码路径,也不能靠 chmod 或 sudo 绕过:
- 先弹系统对话框:用
NSOpenPanel设置canChooseDirectories = true,让用户亲手点选目标文件夹 - 立刻启用访问权:调用
url.startAccessingSecurityScopedResource(),否则后续 open/write 都失败 - 访问完立即释放:必须配对调用
url.stopAccessingSecurityScopedResource(),否则下次启动可能卡住 - 要长期可用:生成
bookmarkData并存进自己容器内(比如Application Support目录),重启后用URL.resolvingBookmarkData(_:)恢复 URL,再 startAccessing 才能继续读写
Info.plist 和 entitlements 必须同步生效
代码写对了,但配置漏一项,照样报错:
-
com.apple.security.files.user-selected.read-write必须设为 true(Xcode Capabilities 中勾选 “User Selected File Access” 可自动生成) - 若用书签持久化,还需开启
com.apple.security.files.bookmarks.app-scope - 访问照片库、通讯录等系统资源,对应 usage description 字段(如
NSPhotoLibraryUsageDescription)也得在 Info.plist 里补全 - 修改后必须重新签名:
codesign --force --deep --sign - /Applications/YourApp.app
常见误判和真限制
看到 “Operation not permitted”,别急着改 chmod 或 chown:
- 检查错误是否发生在访问
~/Desktop、/Volumes/MyDisk等沙盒外路径——大概率是沙盒拦截,不是文件权限问题 - 运行
ls -lOe ~/Documents,若输出含restricted,说明路径本身受 TCC 或沙盒管控 - 临时例外(如
com.apple.security.temporary-exception.files.absolute-path.read-only)不被 App Store 接受,审核直接拒 - 即使用户授了“完全磁盘访问”,沙盒应用仍无法绕过容器隔离——该权限只开放公共区域,不打通沙盒壁垒


















