NSOpenPanel в песочнице — доступ ко всем файлам в папке, выбранной пользователем

Мое изолированное приложение для 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 гласит:

Когда пользователь вашего приложения указывает, что он хочет использовать файл или папку, система добавляет соответствующий путь в песочницу вашего приложения. Скажем, например, пользователь перетаскивает папку ~/Documents на плитку Dock вашего приложения (или на значок Finder вашего приложения, или в открытое окно вашего приложения), тем самым показывая, что он хочет использовать эту папку. В ответ система делает папку ~/Documents, ее содержимое и вложенные папки доступными для вашего приложения.

(выделено мной)


person Nicolas Miari    schedule 18.03.2019    source источник


Ответы (1)


Я принял быстрый ответ @vadian немного преждевременно, но кажется, что я могу получить доступ к индивидуальному файлы внутри выбранной пользователем папки из NSOpenPanel.

Прочитав этот ответ (который я как-то пропустил сначала в своих поисках), я обнаружил, что приведенный ниже код работает:

// 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
    }
}()

Еще одна ошибка, которую я, по-видимому, допускаю, заключается в использовании свойства isFileURL NSURL для различения выбранной папки и отдельного файла: оно также возвращает true для папки!

Поэтому после того, как я переключился с использования panel.directoryURL на использование panel.urls[0] (когда isFileURL равно true), мое приложение пыталось прочитать одно изображение из URL-адреса каталога. Нарушения песочницы нет, но и изображения не прочитаны.

Согласно документам, это свойство возвращает true, «если получатель использует файловую схему» (что бы это ни значило). Я предполагаю, что папки тоже "используют файловую схему". Вместо этого я переключился на использование hasDirectoryPath, как было предложено в этом другом ответе.

person Nicolas Miari    schedule 19.03.2019
comment
Re: Схема URL-адреса - это часть URL-адреса перед двоеточием, которая определяет тип URL-адреса. Распространенными схемами являются http/https (путь к интернет-ресурсу), mailto (адрес электронной почты) и файл (любой объект файловой системы в файловой системе, для которого оценивается URL-адрес) и т. д. Т.е. файл — это сокращение от объекта локальной файловой системы; который включает в себя файлы, папки/каталоги, каналы, устройства; а не о файлах как таковых. ХТН - person CRD; 24.03.2019
comment
@CRD Спасибо, я знал о схемах URL. Все URL-адреса, с которыми я сталкивался, начинаются с file:///... (я предполагаю, что это file:// плюс еще одна косая черта, представляющая корневой каталог...?) - person Nicolas Miari; 25.03.2019
comment
На самом деле это не корень, а разделитель, но думать о нем как о корне, когда путь похож на Unix, в основном безвредно. Синтаксис см. в разделе URI файла. - person CRD; 25.03.2019
comment
@CRD Понятно, еще раз спасибо. Я имею в виду, что в других схемах только две косые черты :-) - person Nicolas Miari; 25.03.2019