DEV Community

Filip Němeček
Filip Němeček

Posted on • Edited on • Originally published at nemecek.be

iOS: Saving files into user’s iCloud Drive using FileManager

As a part of the CloudKit framework your app can save and read files from user’s iCloud Drive. Of course only from specialized folder for your app not all the other files available. Getting it working is a bit complicated because it involves a few discrete steps. Let’s see how to do it 🙂
Please note you need paid developer account to access iCloud features.

Adding capability

The first step is to indicate that your project is going to use iCloud Drive. This is done in the "Signing & Capabilities" tab. Click on "+ Capability". Next select iCloud option.

Now you can specify what you want. For our purposes we want the "iCloud Documents" option.

Also create container for your app with the "+" button. This example below is from my free document scanner app Scan it.

iCloud capability configuration

Modifying Info.plist

The next step is to modify the infamous Info.plist. I would recommend selecting "Open As" option and use "Source Code" so you can work with pretty standard XML. We need to add a quite bit of stuff:



<key>NSUbiquitousContainers</key>
    <dict>
        <key>iCloud.[YOUR_IDENTIFIER]</key>
        <dict>
            <key>NSUbiquitousContainerIsDocumentScopePublic</key>
            <true/>
            <key>NSUbiquitousContainerName</key>
            <string>[YOUR_IDENTIFIER]</string>
            <key>NSUbiquitousContainerSupportedFolderLevels</key>
            <string>Any</string>
        </dict>
    </dict>


Enter fullscreen mode Exit fullscreen mode

In the place of [YOUR_IDENTIFIER] use your app name for example. I don't this this matters much because the folder will be named after your app inside user's iCloud Drive.

Time for the one line of Swift code

The preparation is done at this point and we can move to actual Swift code. If you ever dealt with FileManager then there won't be much new stuff.

Writing and reading files inside iCloud Drive is basically same as writing and reading files inside local Documents directory for your app. The only different part is getting the folder URL.

We can get the URL like this:



let driveURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")


Enter fullscreen mode Exit fullscreen mode

We don't even need to pass the identifier, with nil we get the default (and only one) container.

Note: The appendingPathComponent("Documents") is very important bit and without it your folder will not show inside iCloud Drive (which you can quickly verify via Files app in iOS).

You should absolutely use something like DispatchQueue.global to get the url above because it may take a bit of time for system to find the container (or prepare it first time) before it is ready.

Nice thing about this is that you don't even care about internet connectivity. You can just save the files there and the iOS will synchronize them once it has the opportunity to do so. Pretty neat.

As a last step it is recommended to bump up the app version and build numbers so iCloud correctly registers. I don't know if this is 100% needed but it is super small tweak so why not.

PS: When I first started working with iCloud Drive I could not find many resources and it is possible I left out something important or useful. If that is the case, please let me know in the comments.

Thanks for reading!

--
Need to focus on your iPhone? Get free WebBlock app for scheduled website blocking from the App Store!

Top comments (15)

Collapse
 
usb profile image
Umayanga Alahakoon

Hey Filip,
If you have any free time, can you please write an article on how to download/restore the data of the app from iCloud Drive.

I used this method to save images to iCloud Drive and save the image names on CoreData/CloudKit database. But the app can't get the images from iCloud Drive that are saved into iCloud Drive FROM A DIFFERENT DEVICE (same app and same iCloud user).

I have no idea what causes this problem. All the images are successfully uploaded to the iCloud. The app successfully displays all the images that are saved from the SAME DEVICE even after I delete and reinstall the app.

So, If you have any free time, please consider writing an article on how to download/restore the application’s data from iCloud Drive.

Collapse
 
usb profile image
Umayanga Alahakoon

I use this to get the path of the app's iCloud drive

let driveURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")

then I use this to display the image (on SwiftUI)

Image(uiImage: UIImage(contentsOfFile: driveURL!.appendingPathComponent( <name-of-the-image> ).path) ?? UIImage())

Collapse
 
nemecek_f profile image
Filip Němeček

Hi! That weird. Are you signed into the same iCloud account? I am using my app Scan it on both iPhone and iPad and all files get uploaded to the same iCloud Drive.

On the other hand, if you are doing backup, I would use CloudKit without iCloud Drive because user can manipulate the images in Files app for example.

Thread Thread
 
usb profile image
Umayanga Alahakoon

Yeah, the same iCloud account and I'm not doing backup.
I have no idea what causes this problem.

I'll try something with CloudKit.
Thanks for the reply. Have a great day.

Thread Thread
 
usb profile image
Umayanga Alahakoon

My app's folder doesn't show up inside iCloud Drive in iOS files app. I think this might be the problem.

I've correctly specified the .appendingPathComponent("Documents") part and I can even see all of my saved images via Settings->Account->iCloud->Manage Storage->AppName

This is how I save images to the iCloud Drive

// "imgData" is the jpeg data of an image

let driveURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")

let filePath = driveURL!.appendingPathComponent( <unique-name-of-the-image> )

try imgData.write(to: filePath)

Do you have any clue on what's wrong with my app? (especially on the app's folder doesn't show up inside iCloud Drive)

Thread Thread
 
nemecek_f profile image
Filip Němeček

Did you try bumping up the app and build numbers?

Thread Thread
 
usb profile image
Umayanga Alahakoon

Yeah, but still doesn't work. Anyway, thanks too much for replying me. Have a nice weekend.

Thread Thread
 
nemecek_f profile image
Filip Němeček

Strange, one last thing that occured to me.. What language is your device? Maybe "Documents" works only for English? Which would be crazy but who knows..

Thread Thread
 
usb profile image
Umayanga Alahakoon

It’s English (US)

Thread Thread
 
boxed profile image
Anders Hovmöller

I have the same problem. I do everything in this article, but no folder appears. I tried to add a createDirectory call too, but no dice.

Thread Thread
 
boxed profile image
Anders Hovmöller

Well crap. In my case if I just created a file in the folder it appeared! So seems different from your case.

Collapse
 
usb profile image
Umayanga Alahakoon

Thanks so much for these super clean and detailed instructions 😊

Collapse
 
gangadhar_mamillapalli_cb profile image
gangadhar mamillapalli

Hey Filip,
I was planning to do the same thing using Cloudkit JS in my nodejs server. But am not able to relate things from Swift to javascript side,

Please let me know if you have any suggestions on this

thanks

Collapse
 
bhagyash007 profile image
Bhagyash

the amount of apple generated issues i'm having using iCloud Drive
Took me 1% effort to setup aws s3 with api gateway
I'mma stick with the local disk