Saving files into user’s iCloud Drive using FileManager
This is an example of accessing iCloud Drive and saving files there. Learn how to save files with my guide in iOS.
Published: May 10, 2020 Sponsored See booksAs a part of the CloudKit framework your iOS 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 in Swift 🙂
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.
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>[CONTAINER_IDENTIFIER]</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>[YOUR_IDENTIFIER]</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
In the place of [CONTAINER_IDENTIFIER]
use the same name you used when adding the iCloud capability and creating the actual container. I have "iCloud.ScanIt" as my container identifier, so the exactly same string needs to be used here.
And in the place of [YOUR_IDENTIFIER]
use your app name for example. I don't think this matters much because the folder will be named after your app inside user's iCloud Drive.
Accessing iCloud Drive in 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")
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.
Also before you go check inside Files if the directory is present, save at least one file there.
For example simple text file:
let fileURL = driveURL.appendingPathComponent("test.txt")
try? "Hello word".data(using: .utf8)?.write(to: fileURL)
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!
Thanks for reading!
Uses: Xcode 12 & Swift 5.3