Picking a Folder from iCloud with Document Picker

2.5k views Asked by At

I'm trying to import a folder from iCloud with Document Picker to upload it to a server, using Alamofire. I can import a single file like .txt .pdf files from iCloud, but I can't pick a folder which has some files in it. I'm getting the following error after trying to select a folder:

Unable to load data: Error Domain=NSCocoaErrorDomain Code=257 "The file “xxxx” couldn’t be opened because you don’t have permission to view it." ... {Error Domain=NSPOSIXErrorDomain Code=13 "Permission denied"}}

And here is my code:

someFunctionToGetPickedFilePath = { (filePath) in
        let urlString = filePath.path
        let fileWithPath: URL = URL.init(fileURLWithPath: urlString)

        do {
            let fileData = try Data(contentsOf: fileWithPath)
            // upload the fileData to server with Alamofire upload request
        } catch {
            print("Unable to load data: \(error)")
        }
    }

"filePath" URL in here comes from document picker function like this:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
    // some code 
}

I am trying to find a solution for almost 2 days but I cannot seem to find a solution. How can I pick a folder from iCloud and why am I getting this permission denied error? Any response will be highly appreciated.

2

There are 2 answers

2
Cedan Misquith On BEST ANSWER

You are getting this error because you are getting the path of the folder in which your files exist and like @ivan-ičin has said in the comments you cannot pick an entire folder from iCloud according to the documentation.

So if you are trying to upload all the files of a specific folder to your server i would suggest you get the URL of the folder and then using the below code you can get a list all the files present in that folder.

Here is how you can get a list of all the files present in the documents folder that you are trying to pick.

let fileManager = FileManager.default
let documentsURL = "YOUR FOLDER URL"
//If all files are in your app document directory then use this line
//fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]

do {
    let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
    // Append files to an array here and then iterate the array later and upload files to server one by one.
} catch {
    print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
} 

Once you get the URLs you can append them to an array and upload them one by one to your server using Alamofire.

0
Adrian Sluyters On

Remember that when it comes to iCloud that you're in a Sandbox so you need to use the FileManager to get the appropriate files.

e.g.

  1. Make sure that "iCloud Documents" is checked in the project
  2. Specify Container e.g. the container you specified on developer.apple.com. Xcode will do this for you automatically and will appear as something like iCloud.com.yourapp.identifier.whatever.abb
  3. Make sure iCloud is enabled for you app, as again, Xcode will do this for you if you've goo your developer id set up in it correctly (Xcode -> Peferences -> Accounts (tab)... Add it there..

Now with some code magic you can get this going.. Though this is a little more complicated, its the correct way (a little too correct IMHO):

https://theswiftdev.com/2018/05/17/how-to-use-icloud-drive-documents/

But you need to rely on FileManager (old NSFileManager)