Warm tip: This article is reproduced from stackoverflow.com, please click
ios swift icloud icloud-drive uidocumentbrowservc

Cannot access/import contents of iCloud file picked in iOS 11 document browser

发布于 2020-04-07 10:08:18

Besides opening and saving its own custom documents, my iOS 11 document browser-based app should be able to import an appropriately formatted text file and convert it into a document of its own.

However, when picking a text file in the document browser, the app is able to access its contents (and then perform the conversion) only if the selected file is in local storage, but fails to access the contents when the file is stored in iCloud.

A simplified, commented version of the code I am using for the documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) delegate method is provided below:

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!)
        }
    }
}

The info.plist file declares both the custom document and public.text as Document Types (with the appropriate Role and Handler rank), and the custom document as Exported UTI. If the file picked is a custom document, everything works fine, no matter if the file is local or in iCloud.

As the importing works when the file is in local storage, I thought it may be an issue of iCloud permissions, even if Apple docs for UIDocumentBrowserViewController state:

The system automatically handles access to iCloud for you; you don't need to enable your app’s iCloud capabilities.

However, trying to add iCloud capabilities to my app's entitlements did not solve the problem (and actually made it worse, in the sense that the exact same code was now saving newly created documents in the default iCloud container for the app, which is not the same iCloud Drive location used by the document browser, so that all documents became "invisible" to the browser - but I digress...).

Another "fun" element is that I also implemented a UIDocumentPickerViewController in the app to import additional content from a text file into an already open custom document. The code I use is basically the same as above... and it works perfectly, independently of whether the text file is in local storage or iCloud! This could reinforce the view that the problem is linked to a specific permission issue with UIDocumentBrowserViewController.

So, in summary: what could I do to access the content of text files stored in iCloud and convert them to custom documents of my app? Thank you in advance for any suggestions (and please be gentle if there are issues with the formulation of the question - this is my very first stackoverflow question after months of lurking!).

Questioner
emime
Viewed
36
3,653 2019-01-24 11:52

I’m not 100% sure but I believe you need to call startAccessingSecurityScopedResource on that URL to consume the sandbox extension vended to you by the document browser. Don’t forget to call stopAccessing once you are done in order not to leak kernel resources. Also, if you are not really editing that document, you might be looking for a UIDocumentPickerViewController instead? It’s weird for the user to open a file and then end up editing another. Isn’t it a better UX to start a new document, and then import the text file into it with the picker?