Невозможно получить доступ / импортировать содержимое файла iCloud, выбранного в браузере документов iOS 11

Помимо открытия и сохранения собственных пользовательских документов, мое приложение на основе браузера для документов iOS 11 должно иметь возможность импортировать текстовый файл с соответствующим форматированием и преобразовывать его в собственный документ.

Однако при выборе текстового файла в браузере документов приложение может получить доступ к его содержимому (а затем выполнить преобразование) только в том случае, если выбранный файл находится в локальном хранилище, но не может получить доступ к содержимому, когда файл находится в хранится в iCloud.

Упрощенная версия кода с комментариями, который я использую для метода делегата documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]), представлена ​​ниже:

func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {

    guard let sourceURL = documentURLs.first else { return }

    // Check extension to verify if it is a custom document
    if sourceURL.pathExtension == "mydoc" {

        // If it is a custom document, we present it directly
        // (the presentDocument method is a standard implementation from Apple docs)
        presentDocument(at: sourceURL)

    } else {

        // Otherwise, we suppose the file is a text file to be imported
        // We first create a new document, then try to import the contents of the text file     
        let url = FileManager().temporaryDirectory.appendingPathComponent("New Document").appendingPathExtension("mydoc")
        let doc = MyDocument(fileURL: url)

        do {
            let textFileContents = try String(contentsOf: sourceURL)
            // It works fine if the text file is in local storage
            // Here the document model is updated by converting the contents of the text file 
            // (code omitted, it is actually a method in the MyDocument class)
            // ...
        } catch {
            // Produce error message: cannot access text file
            // The error message is always produced if the text file is in iCloud storage!
        }

        // Save and close the document with standard code, e.g.:               
        doc.save(to: url, for: .forCreating) { (saveSuccess) in
            guard saveSuccess else { return }
            doc.close(completionHandler: { (closeSuccess) in
                guard closeSuccess else { return }  
            })

        // Reveal and import the document
        self.revealDocument(at: url, importIfNeeded: true) { (revealedDocumentURL, error) in
           if let error = error {
               // Handle the error appropriately
               return
           }
           // Present the Document View Controller for the revealed URL
           self.presentDocument(at: revealedDocumentURL!)
        }
    }
}

В файле info.plist пользовательский документ и public.text объявляются как типы документов (с соответствующей ролью и рангом обработчика), а пользовательский документ - как экспортированный UTI. Если выбранный файл является настраиваемым документом, все работает нормально, независимо от того, является ли файл локальным или находится в iCloud.

Поскольку импорт работает, когда файл находится в локальном хранилище, я подумал, что это может быть проблема с разрешениями iCloud, даже если в документации Apple указано UIDocumentBrowserViewController:

Система автоматически обрабатывает доступ к iCloud за вас; вам не нужно включать возможности iCloud вашего приложения.

Однако попытка добавить возможности iCloud в права моего приложения не решила проблему (и фактически усугубила ситуацию в том смысле, что тот же самый код теперь сохранял вновь созданные документы в контейнере iCloud по умолчанию для приложение, которое отличается от того же местоположения iCloud Drive, которое используется браузером документов, так что все документы стали «невидимыми» для браузера - но я отвлекся ...).

Еще один "забавный" элемент заключается в том, что я также реализовал UIDocumentPickerViewController в приложении для импорта дополнительного содержимого из текстового файла в уже открытый пользовательский документ. Код, который я использую, в основном такой же, как и выше ... и он отлично работает, независимо от того, находится ли текстовый файл в локальном хранилище или iCloud! Это может укрепить мнение о том, что проблема связана с конкретной проблемой разрешений с UIDocumentBrowserViewController.

Итак, вкратце: что я мог сделать, чтобы получить доступ к содержимому текстовых файлов, хранящихся в iCloud, и преобразовать их в пользовательские документы моего приложения? Заранее благодарим вас за любые предложения (и, пожалуйста, будьте осторожны, если есть проблемы с формулировкой вопроса - это мой самый первый вопрос о stackoverflow после нескольких месяцев скрывания!).


person emime    schedule 10.04.2018    source источник


Ответы (2)


Я не уверен на 100%, но полагаю, что вам нужно вызвать startAccessingSecurityScopedResource по этому URL-адресу, чтобы использовать расширение песочницы, предоставленное вам браузером документов. Не забудьте позвонить stopAccessing, когда закончите, чтобы не допустить утечки ресурсов ядра. Кроме того, если вы на самом деле не редактируете этот документ, вы можете вместо этого искать UIDocumentPickerViewController? Странно, когда пользователь открывает файл, а потом редактирует другой. Не лучше ли начать новый документ, а затем импортировать в него текстовый файл с помощью средства выбора?

person Thomas Deniau    schedule 11.04.2018
comment
Спасибо большое, сработало! Вызов startAccessingSecurityScopedResource до того, как функция импорта сделала трюк. Я видел ваш ответ на ссылке, но сосредоточился на части закладки ( что не сработало) вместо этого в части запуска / остановки доступа. Что касается вашего вопроса, я действительно реализовал UIDocumentPickerVIewController, но поскольку ВСЕ документы моего приложения должны начинаться с файла csv (сгенерированного другим приложением), я подумал, что было бы полезно просто выбрать их в браузере документов, чтобы запустить новый документ. - person emime; 11.04.2018

небольшой всплывающий фрагмент: (Swift 5.x)

    public func documentBrowser(_ controller: UIDocumentBrowserViewController,
                                  didPickDocumentsAt documentURLs: [URL]) {

            dismiss(animated: true, completion: nil)

            self.importAll(urls: documentURLs)
        }



    final func importAll(urls: [URL]) {

        //TODO: use timer/loop/async stuff..
        // for multiple files..

        urls.forEach { (url: URL) in

            let secured = url.startAccessingSecurityScopedResource()

            = myImportInSessionFrom(url: url)

            if secured { url.stopAccessingSecurityScopedResource() }

        }
 }
person ingconti    schedule 31.01.2020