iOS Extensions: Document Provider Tutorial
- Getting Started
- Architecture of CleverNote’s Data Storage
- Where CleverNote’s Files Are Currently Stored
- Allowing Data to Be Shared Between Apps
- Providing Files to Other Developers’ Apps
- Adding Your Document Provider Extension
- Setting Up App Groups
- Storing to the Shared Container
- Creating the Document Picker Experience
- Import/Open Experience
- Export/Move Experience
- Hooking up the File Provider
- Where to Go From Here?
Note: This tutorial has been updated (23/09/2016) to use Xcode 8, iOS 10, and Swift 3.
Kids on the playground are told to share and play nice, or else they get put in time-out; these days, with users craving seamless interactivity, apps have to do the same (or they’ll get deleted). Users don’t want to leave one app to take advantage of another app’s capabilities or access another app’s files, so how can you extend the functionality of your app to be used by other apps on a device? The answer is in this Document Provider tutorial: iOS extensions and the Document Provider extension.
The Document Provider extension (commonly referred to as the document provider) allows an app to share its documents with the other apps on a user’s device in a safe and convenient way. If you have ever used the Document Picker, you might have admired all the apps in the Locations section. Maybe you wondered: how do I get my app to show up there?
Today, young grasshopper, you’ll find out. :]
In this Document Provider tutorial, you’ll be working on an app called CleverNote. CleverNote starts out as just an app that allows a user to create and edit simple text notes. You’ll be adding the document provider, which will allow users to do the following:
- Open and edit CleverNote notes in other apps.
- Move notes into the CleverNote app.
- Import notes from other apps into CleverNote.
- Export notes from CleverNote to other apps.
These documents aren’t going to provide themselves, so let’s get started!
Download the starter project here. Build and run (Product \ Run or ⌘R) the project in Xcode, and you’ll see the following:
Tapping on the + button in the upper right allows you to create a new note. After you add a title and text, hitting the save button will save the note to your device’s document storage directory. That’s great … except it can’t be accessed by other devices, which means your app exists in its own little closed world, and your user is getting annoyed. But don’t worry—you’re about to change all of that. ;]
Architecture of CleverNote’s Data Storage
In order to best understand how to share data, it is important to have a solid understanding of the iOS file system.
Where CleverNote’s Files Are Currently Stored
At this point, the notes created in the CleverNote app are stored in the Documents Directory. This is the directory where you can store user-generated content.
Note: When using the iOS Simulator, you can open the directory that contains these user-generated files. This is very helpful when debugging. To do this, open Note.swift and uncomment the
localDocumentsDirectoryURL() method, then run the app. You should see something like this print in the Console:
That is the URL to the iPhone Simulators Documents directory. Copy that URL (excluding the
file://prefix), open Finder on your Mac, hit CMD + SHIFT + G to jump to a folder, and paste the URL. Any created notes should show up right there. To learn more about the different standard iOS Directories, check this out.
Currently, the notes you’re creating are not visible to other apps because of the idea of an app’s sandbox.
You can think of the sandbox as a safe area for the app to play. An app should never be playing, or functioning, outside of its designated sandbox. In the above diagram, CleverNote sits on top of its own sandbox, but no other apps are allowed to play in CleverNote’s sandbox. Even an app extension does not have access to anything in the app’s sandbox.
Allowing Data to Be Shared Between Apps
iOS 8 brought us the concept of an app group: a collection of apps created by the same development team that allows two or more apps to access the shared data containers.
This concept allows apps or extensions to have a shared set of files. Awesome, right? But only if your user only uses your apps. What about helping your app play nice with apps from different designers?
Providing Files to Other Developers’ Apps
If your app needs to share its files with apps that are not part of your app group, this can be done with a
UIDocumentProvider extension that has access to your app group. This extension allows other developers’ apps to access your files using the
UIDocumentPicker, as seen below.
UIDocumentProvider provides four modes of interaction when accessing files:
In the import operation, the data is duplicated from your app’s container to the third-party app.
In the open operation, the third-party app is able to modify a file from your app’s container and then save it back to your app’s container.
In the export operation, the data is duplicated from the third-party app to your app’s container.
In the move operation, the third-party app moves a file from its container to your app’s container.
Now that you know how the data is currently stored and the operations other apps might want to perform on your data, it’s time to start providing some documents!
Adding Your Document Provider Extension
To add the Document Provider extension, first select the CleverNote project in the Project Navigator and click the + button to add a target (the + button is at the very bottom of the Targets list, next to the filter). Select iOS/Application Extension/Document Provider and click Next. Type Picker for the Product Name and make sure to check the box to Include a File Provider Extension; this will be important later. If Xcode asks if you would like to activate the scheme, click Activate. This will allow you to build and debug the extension.
At this point, your targets should look like the image below:
Let’s look through the Project Navigator to see what these targets have added to the project.
Under the Picker directory, you’ll see that Xcode has generated a
DocumentPickerViewController. This is a subclass of
UIDocumentPickerExtensionViewController, displayed inside a third-party application when using the Document Picker extension.
Under the PickerFileProvider directory, you’ll see the
FileProvider class Xcode generated. The
FileProvider coordinates all of the reading and writing during the file operations.