You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS SwiftUI中如何访问用户选定目录下的只读文件?(权限配置后失败)

问题:macOS Sandbox环境下无法访问选定文件夹内的文件

环境信息

  • SDK:macOS 14.0
  • Xcode:15.0

我查阅了大量相关解决方案,但均未解决问题——目前无法访问用户选定文件夹下的文件内容。

已执行的配置与代码

  1. App Sandbox权限配置:已勾选「User Selected File」的读写权限
  2. 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
    }
}
  1. 文件夹内容访问逻辑:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:58:10