SwiftUI fileImporter获取目录后FileManager枚举器返回nil(沙箱问题)
问题解答
核心结论:user-selected权限确实适配.fileImporter,但枚举目录时必须处理安全范围书签(Security-Scoped Bookmarks)
通过.fileImporter拿到的目录URL,在沙箱环境下默认无法直接让FileManager枚举其内容——哪怕你配置了user-selected权限。沙箱要求你显式发起临时授权,才能访问该目录及其子内容,这就是问题的根源。
具体解决步骤
获取URL后启动安全范围访问
在.fileImporter的结果回调里,必须调用startAccessingSecurityScopedResource()获取临时访问权限,枚举完成后再调用stopAccessingSecurityScopedResource()释放权限:.fileImporter( isPresented: $showImporter, allowedContentTypes: [.folder], allowsMultipleSelection: false ) { result in switch result { case .success(let urls): guard let targetURL = urls.first else { return } // 启动安全范围访问,失败则直接返回 guard targetURL.startAccessingSecurityScopedResource() else { print("无法获取目录访问权限") return } // 用defer确保权限一定会被释放 defer { targetURL.stopAccessingSecurityScopedResource() } // 此时再创建枚举器就可以正常获取文件了 if let enumerator = FileManager.default.enumerator(at: targetURL, includingPropertiesForKeys: nil) { while let fileURL = enumerator.nextObject() as? URL { print("找到文件:\(fileURL.lastPathComponent)") } } case .failure(let error): print("导入失败:\(error.localizedDescription)") } }权限配置无需修改
你当前的com.apple.security.files.user-selected.read-only配置是正确的,换成读写权限com.apple.security.files.user-selected.read-write也能正常工作,但核心还是必须调用上述的安全范围访问方法——没有这一步,沙箱会直接拦截枚举器的访问请求,导致nextObject()返回nil。
移除沙箱后正常的原因
移除沙箱等于关闭了系统的权限隔离机制,App可以不受限制地访问任意文件路径,自然不会出现枚举失败的问题。但这种方式无法通过Mac App Store的审核,所以必须保留沙箱并正确处理安全范围权限。
内容的提问来源于stack exchange,提问作者bauerMusic
相关产品推荐
相关产品推荐

