【问题标题】:NSOpenPanel under Sandbox - Access All Files inside User Selected folder沙盒下的 NSOpenPanel - 访问用户选定文件夹中的所有文件
【发布时间】:2019-08-08 15:05:54
【问题描述】:

我的沙盒 macOS 应用程序按照惯例通过NSOpenPanel 模态窗口导入用户选择的图像文件。

首先,我将面板配置为canChooseDirectories = false,并将allowedFileTypes 属性设置为NSImage.imageTypes。到目前为止一切顺利。

使用该应用程序后,我意识到我想要导入的图像通常被分组在一个文件夹中,其中没有任何其他内容。如果我可以让用户只选择包含文件夹并在“批发”中导入图像,那就太好了,所以我采用了这个代码:

let panel = NSOpenPanel()

panel.allowsMultipleSelection = true
panel.canChooseDirectories = true
panel.canCreateDirectories = false
panel.canChooseFiles = true
panel.allowedFileTypes = NSImage.imageTypes

panel.begin { [unowned self] (result) in
    guard result == .OK else {
        return // User cancelled
     }

     // Read all selected images:

     let urls: [URL] = {
        if let directory = panel.directoryURL {
            // .........................................
            // [A] One directory selected:

            do {
                let urls = try FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil, options: [])
                return urls
            } catch {
                // (I ALWAYS END UP HERE)

                print(error.localizedDescription)
                return [] 
            }
        } else {
            // .........................................
            // [B] One or more files selected:

            return panel.urls
        }
     }()

 // (next: read individual urls...)

...但是try 语句总是失败catch 块被执行并且抛出的错误是:

“无法打开文件“MyImageFolder”,因为您无权查看它。”

对于沙盒应用,有没有办法解决这个问题?我忘记了哪些可以让我读取用户选择的文件夹的内容?


附录: Apple's documentation 声明:

当您的应用程序的用户指定他们要使用文件或文件夹时,系统会将关联的路径添加到您的应用程序的沙箱中。例如,用户将 ~/Documents 文件夹拖到应用程序的 Dock 磁贴(或应用程序的 Finder 图标,或应用程序的打开窗口)上,从而表明他们想要使用该文件夹。作为响应,系统使 ~/Documents 文件夹、其内容及其子文件夹可供您的应用使用。

(强调我的)

【问题讨论】:

    标签: macos cocoa sandbox nsopenpanel


    【解决方案1】:

    我有点过早地接受了@vadian's quick answer,但我似乎可以NSOpenPanel 访问用户选择的文件夹中的各个文件。

    在阅读了this answer(起初我在搜索中不知何故错过了)之后,我发现下面的代码有效:

    // Warning! This code does not deal with the user selecting 
    // multiple folders!
    
    let urls: [URL] = {
    
        if inputURLs.count == 1, inputURLs[0].hasDirectoryPath {
            // Folder; Read its contents:
            do {
                let urls = try FileManager.default.contentsOfDirectory(at: inputURLs[0], includingPropertiesForKeys: nil, options: [])
                    return urls
    
            } catch {
                // (todo: Handle Errors)
                return []
            }
        } else {
            // One or more images; Read them directly:
            return inputURLs
        }
    }()
    

    我似乎犯的另一个错误是使用NSURLisFileURL 属性来区分所选文件夹和单个文件:它也为文件夹返回true

    因此,在我从使用 panel.directoryURL 切换到使用 panel.urls[0](当 isFileURLtrue 时)后,我的应用程序试图从目录 URL 中读取单个图像。没有沙盒违规,但也没有读取图像。

    根据文档,该属性返回true“如果接收者使用文件方案”(无论这意味着什么)。我猜文件夹也“使用文件方案”。 正如this other answer 中所建议的,我改用hasDirectoryPath

    【讨论】:

    • Re: URL "scheme" - 它是 URL 冒号前的部分,它决定了 URL 的种类。常见的方案是 http/https(互联网资源路径)、mailto(电子邮件地址)和文件(评估 URL 的文件系统中的任何文件系统对象)等。即“文件”是“本地文件系统对象”的简写;其中包括文件、文件夹/目录、管道、设备;而不是关于文件本身。 HTH
    • @CRD 谢谢,我知道 URL 方案。我遇到的所有 URL 都以 file:///... 开头(我假设是 file:// 加上另一个代表根目录的正斜杠...?)
    • 它实际上不是根,而是一个分隔符,但是当路径是类 Unix 时将其视为根主要是无害的。语法见File URI
    • @CRD 我明白了,再次感谢。我的意思是,其他方案只有两个斜杠:-)
    猜你喜欢
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 2018-04-17
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 1970-01-01
    相关资源
    最近更新 更多