macOS SwiftUI中如何访问用户选定目录下的只读文件?(权限配置后失败)
问题:macOS Sandbox环境下无法访问选定文件夹内的文件
环境信息
- SDK:macOS 14.0
- Xcode:15.0
我查阅了大量相关解决方案,但均未解决问题——目前无法访问用户选定文件夹下的文件内容。
已执行的配置与代码
- App Sandbox权限配置:已勾选「User Selected File」的读写权限
- SwiftUI文件选择实现:
Button("open file") .fileImporter( isPresented: $indexModel.openFileImporter, allowedContentTypes: [.movie, .avi, .mpeg4Movie, .directory], allowsMultipleSelection: true ) { results in do { let selection = try results.get() try self.openSelectedPath(selection) } catch let err { indexModel.errorMsg = err.localizedDescription indexModel.showError = true } }
- 文件夹内容访问逻辑:
if selection.hasDirectoryPath { let files = try FileManager.default.contentsOfDirectory( at: selection, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles] ) files.enumerated().filter { _, file in // 尝试授权但全部失败 guard file.startAccessingSecurityScopedResource() else { print("\(file.lastPathComponent) cannot access") return false } let isMKV = file.pathExtension.compare("mkv", options: .caseInsensitive, range: nil, locale: nil) == .orderedSame return file.isFileURL && (isMKV || file.contains(.movie) || file.contains(.avi) || file.contains(.mpeg4Movie)) } return }
当前问题:文件夹内所有文件调用startAccessingSecurityScopedResource()均返回false,无法访问。
解决方案
优先给父文件夹授权,而非子文件
沙箱仅会对用户直接选择的文件夹URL授予安全作用域权限,通过contentsOfDirectory获取的子文件URL没有独立权限。需要先对父文件夹调用授权,遍历子文件时无需单独授权。修改后的代码示例:func openSelectedPath(_ selection: URL) throws { guard selection.hasDirectoryPath else { return } // 给父文件夹开启安全作用域访问 guard selection.startAccessingSecurityScopedResource() else { throw NSError(domain: "AccessError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法访问选定文件夹"]) } // 操作完成后必须停止授权,避免资源泄漏 defer { selection.stopAccessingSecurityScopedResource() } let files = try FileManager.default.contentsOfDirectory( at: selection, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles] ) let validFiles = files.filter { file in // 简化MKV格式判断 let isMKV = file.pathExtension.lowercased() == "mkv" // 用UTType判断更可靠的视频类型 let isSupportedMovie = file.typeIdentifier == kUTTypeMovie as String || file.typeIdentifier == kUTTypeAVIMovie as String || file.typeIdentifier == kUTTypeMPEG4 as String return file.isFileURL && (isMKV || isSupportedMovie) } // 这里处理筛选后的有效文件 }确认Sandbox权限配置
确保「User Selected File」的读写权限已正确勾选,该权限支持访问选定文件夹的所有子内容,无需额外配置其他权限。优化文件类型判断逻辑
避免使用file.contains(.movie)这类不准确的写法,改用typeIdentifier匹配UTType,或直接比较小写的文件扩展名,提升判断准确性。严格管理安全作用域生命周期
必须在资源使用完毕后调用stopAccessingSecurityScopedResource(),使用defer语句可以保证无论代码是否抛出错误,都会执行停止操作,防止沙箱权限泄漏。
内容的提问来源于stack exchange,提问作者fool
相关产品推荐
相关产品推荐

