macos 应用沙盒是必须遵循的访问契约,需在 entitlements 和 info.plist 中同步配置权限、通过用户主动选择获取安全作用域凭证、严格管理资源访问生命周期,并确保签名与调试验证到位。

macOS 应用沙盒不是障碍,而是必须遵循的访问契约。开发者不能跳过它,但可以精准申请、合规使用——关键在于把“用户授权”变成流程的一部分,而不是权限配置的终点。
权限声明必须在 entitlements 和 Info.plist 中同步生效
仅勾选 Xcode Capabilities 里的选项不够,需人工核对底层配置是否完整:
-
entitlements 文件中必须显式包含:
com.apple.security.app-sandbox(设为true),以及具体能力键,例如:com.apple.security.files.user-selected.read-write、com.apple.security.network.client -
Info.plist需补充对应用途描述键,如
NSCameraUsageDescription、NSDocumentsFolderUsageDescription,否则系统不会弹出首次授权提示 - 修改后必须重新签名:
codesign --force --deep --sign - /Applications/YourApp.app,否则新权限不生效
文件访问必须由用户主动触发并持久化凭证
沙盒下没有“一次授权,永久可用”的路径。每次访问受保护位置前,都需满足三个条件:
- 用
NSOpenPanel或NSSavePanel弹出系统对话框,让用户点击选择(canChooseDirectories = true) - 拿到 URL 后,立即调用
url.startAccessingSecurityScopedResource()开启临时访问 - 访问结束后,务必配对调用
url.stopAccessingSecurityScopedResource();若需长期访问,用url.bookmarkData(options: .withSecurityScope)生成书签,并存入自身容器目录(如applicationSupportDirectory)
调试时快速定位沙盒拦截原因
报错 “Operation not permitted” 不代表代码写错,大概率是沙盒策略生效:
- 打开「活动监视器」→ View → Columns → 勾选 Sandbox,确认进程确为沙盒状态
- 终端执行:
codesign -dv --entitlements :- /Applications/YourApp.app,检查输出中是否有你声明的权限键 - 查控制台(Console)日志,筛选关键词
sandboxd或你的 bundle ID,看被拒绝的是哪类操作(如file-read-data、sysctl-read) - 运行
ls -lOe ~/Documents,若含restricted字样,说明该路径本身受 TCC 或沙盒双重管控
避免常见合规性陷阱
很多崩溃或静默失败,源于看似细微的疏漏:
- 书签数据不能存到
/tmp、~/Desktop或全局路径——沙盒应用读不到这些地方,必须存在自己容器内 - 不要在主线程长时间持有
startAccessing,尤其不能跨异步任务或后台线程;应严格遵循“开→用→关”最小作用域原则 - 重启后恢复书签时,
URL.resolvingBookmarkData(_:)返回的 URL 仍需再次startAccessing才能读写,缺一不可 - 开发阶段可临时用
com.apple.security.temporary-exception.files.absolute-path.read-write测试,但发布前必须移除,App Store 审核会拒收











