[ Music ]
[ Applause ]
Good morning, and welcome to Managing Documents In Your iOS Apps.
I'm Brandon Tennant, a software engineer here at Apple and the Document Management team.
And, later I'll be joined by my colleagues Thomas Deniau and Rony Fadel.
So, today we're going to give you an overview of what document management on iOS is.
And, then we'll share a few new things in this area.
Then, Thomas will come up on stage to show you how to use the Document Management API in your apps.
And, finally, Rony will join us onstage to show you a few tips and tricks for raising the bar in your application.
So, let's get started with a refresher about what document management on iOS is.
It's a collection of technologies.
First, there's an API for application developers.
For cloud vendors, there's also the File Provider API.
And, there's also the Files app.
In iOS 11, we introduced UIDocumentBrowserViewController.
And, also significantly revamped UIDocumentPickerViewController.
Using this new controller in your app, your customers will be able to manage and browse their files from all of their favorite cloud vendors.
There's also powerful Search that searches across all of these cloud vendors.
They'll be able to favorite Folders, and those favorite Folders will appear in the sidebar.
And, they'll be able to organize their files using Tags.
Recently used files also appear in the Recents tab.
So, by using UIDocumentBrowserViewController in your app, you'll be giving your customers a consistent experience, by bringing all of the power of Files into your app.
It eliminates the need for you to write your own document browser.
This allows you to focus on perfecting the experience your customers will have when viewing or editing documents in your app.
To get started with this, see last year's session, "Building Great Document-based Apps in iOS."
There's also API for cloud vendors.
This is called the File Provider API.
You use this to write file provider extensions, and also custom UI actions, including the account sign-in screen.
For application developers, you don't need to use this API for people to access your files.
So, when you write a file provider extension, it will appear in the Files app, and in UIDocumentBrowserView Controllers, under the Locations tab under the Locations section.
Also, because sign-in is implemented using FPUI ActionExtensionViewController, you'll want to use this so you can reduce friction for your customers by making logging into your service easier.
Let's go through a few examples of that.
First, in this example, what you can do or, what the user is able to do, is sign into their service, without being interrupted from their workflow.
They don't have to leave the app.
They can just sign in and continue going along their business.
An example of what to try and avoid, would be something like this, where there's redundant UI elements or branding onscreen.
You can see the example of two nav bars, or two Cancel buttons.
And, another example to try and avoid, is having a simple Sign In button, where all it does is launch to your application.
This interrupts the customer's workflow.
So, try to avoid doing that.
Lastly, we've seen great adoption from all of you developers and cloud vendors over the course of the last year.
So, there's a lot of applications that use this technology already.
So, now is a great time to try adopting UIDocumentBrowserViewController in your application today.
And, if you're a cloud vendor that hasn't yet already provided a file provider extension, now's the time to do so.
So, let's talk about a few new things.
First, for cloud vendors, we've seen some of the difficulties in making a file provider extension.
And, what we're happy to announce today is there's a new tool for you.
It's called the File Provider-Validation tool.
This tool will guide you will help will run tests, and show you the issues with your file provider extension, and guide you towards fixing those.
It's available for download today from developer.apple.com.
And, when you download it, you'll get a couple of things.
You're going to get a set of source files that you'll need to add to your file provider extension project, and an iOS application to install and run on your iPad.
Once you've modified your file provider project, installed the app on your iPad, and run it, you'll be greeted with a screen that looks like this.
Your file provider will be listed will be shown on the left side, and when you tap that, there'a Run button that you can press to run our full suite of tests against your file provider extension.
When you've done that, you'll see a list of successes and failures.
You'll want to tap on the failure to dig deeper, and find the issues in your code.
We'll be able to help you through this at the labs on Thursday and Friday.
Also, an exciting new thing this year announced was Siri shortcuts.
And, we're happy to say that Siri shortcuts are coming to file provider extensions.
What this does, is it surfaces recently used documents that were opened or created, and it makes them visible either in Search or on the Lock Screen.
You'll also be able to your customer will also be able to make shortcuts that are synced across devices.
And, it's important to note that they're synced across devices, because in order to support this, your file provider will need to use unique identifiers for each file across all of the devices for a given customer.
If this is true, or you can make this happen, all you need to do to support Siri shortcuts in your file provider extension is to add NSFileProvider UsesUniqueItemIdentifiers AcrossDevices to your file provider extension's info.plist file.
Once you've done that, and submitted to the Store, you're done.
For application developers, there's nothing you need to do.
For information about Siri shortcuts, check out yesterday's session, "Introduction to Siri Shortcuts."
Also this year, we're happy to announce that we're releasing the Particle Sample app.
This was sample code that we used in last year's session to demonstrate how to use UIDocumentBrowserViewController in your app.
It looks like this, and it uses UIDocumentBrowserViewController as its main viewController.
It defines a file format.
It implements state restoration, and imports assets using UIDocumentPickerViewController.
You'll be able to download this today.
The link is available in the WW app, and you'll also be able to search for it online.
And, that's Particles.
So, with that, I'd like to introduce Thomas onto the stage.
[ Applause ]
I'm Thomas, a software engineer on the Documents Management team.
And, I'm going to take you through how you can leverage the document management features of iOS in your app.
Together, we're going to discuss what the Document Picker and Document Browser are, when and how to use them.
Then, we'll add a document picker to our demo app, Particles.
And, finally, we talk about document types, and how to configure them properly in Xcode.
So, what does interacting with documents mean nowadays?
Of course, it means that you need to provide UI to let your customers organize their documents.
Starting with the ones in your app container.
But, because most documents are in the cloud nowadays, it means that you need to let them access documents stored in the cloud, and in other apps.
How do you do this?
Well, we have two solutions for you.
The Document Picker and the Document Browser.
What are the differences between these two?
Well, both let you browse files stored locally on your iOS device, and in various cloud services.
And, both let you access files from other apps.
However, they have different use cases.
You [inaudible] Document Picker shortly, for a short period of time, for a quick user interaction with the files you want to reach.
The Document Browser, on the other hand, is supposed to be the main document browsing UI of your app.
Let's start with the Document Browser.
As Brandon mentioned, the document browser is what you see when you launch any of the UI applications.
If your app is document-based, you should probably use a document browser to display these documents.
And, if you choose to do so, this is what your customers will see when they launch your app.
They immediately get to the files, which is what matters.
The Document Browser is full screen, and it lets your customers open and organize the documents that your app handles.
As Brandon mentioned, it has all the features of the Files app.
So, Search, Tags, Favorites, Recents, all of this comes for free, and we do all of the editing for you.
It can be customized with your own buttons, such as the [inaudible] button in the top right corner, or to match your application's look.
As you can see, numbers and keynote look very different, yet both are based on the Document Browser controller.
Of course, once your customer opens a document, you get to present your own UI on top of the browser to present your documentation UI for example.
Now, because the Document Browser is the entry point of your app, it is best to make it the root view controller.
However, we got a lot of feedback over the last year from you, saying it was not always easy to make it the root view controller.
If that is the case, we want to clarify the guideline we gave last year.
The Document Browser can also be presented [inaudible] full screen, likely shortly after launch.
However, it is still meant to be the starting point of your app.
In document-based apps, what we should see first are the documents.
So, we do not recommend making it possible to get out of the browser.
If you think you need to hide the browser, maybe what you might be looking for is Document Picker, which we are going to discuss next.
How to get started with a new Document Browser controller.
You can start a new app in Xcode, and use the document-based app template.
And, this template gives you Document Browser [inaudible] based app.
If you have an existing app, and want to add a DocumentBrowserViewController to it, you can drag a Document Browser to your storyboard, and use the Initial View Controller checkbox in Xcode.
Once you have the Document Browser controller, you can customize it.
You can add your own buttons to the bars and menus.
And, you can set your own colors and themes to match your app's look.
You can also customize the open and close document animations so that you get a nice zoom-in transition from your document's [inaudible] to your own document addition UI.
To learn all about this, please watch last year's session, where we have covered this in detail.
And, as Brandon mentioned, we have made the sample app that session last year, available as sample code today.
Now, the Document Picker is a different thing.
You use it to let your customers open documents or assets stored in the cloud, or stored in other apps, but it is only shown to let them choose a file, and then it goes away.
The Document Picker is what we use in Mail.
When you want to attach a file to an email, you tap the Add Attachment button, and this sheet pops up.
This is a document picker.
You choose a file to attach, and the sheet goes away.
Same thing in iWork.
If you want to attach a PDF, insert the PDF in your Pages document.
You're going to tap this Insert From button, and the same sheet pops up.
You choose a file, it goes away.
So, if you need to display user interface to let your customers open view things from the cloud, and then hide it once the file is chosen, the Document Picker is a great option for you.
Why do we need to give you the Document Picker?
Because as we have said, documents might be in multiple locations.
They can be in the cloud, or in other app containers.
And, by default, you do not add access to these.
So, you need something to let you access, copy, and move documents between these locations, and this is what the Document Picker does.
It goes away once the files get chosen, so if you want something which stays onscreen for a long time, you should check out Document Browser instead.
What can you do with Document Picker?
You can use it for multiple things.
You can use it to access files in the cloud directly.
Now, creating copies, you can use it to move files to the cloud to implement a safety cloud feature.
And, getting copies of documents is often confusing, but if you really want to, you can use it to copy things from and to the cloud.
So, let's say we want to let our customers access a movie they've stored in the cloud.
This is a great use of Document Picker controller.
You create a Document Picker controller, and you specify the types of file you want your users to choose as a first document.
And, the second document is one of the constants we have described on the previous slide.
Then, you set the Document Picker delegate, because this is how we get notified that your customer has chosen their file, and you present it.
Once the file is chosen, you're going to get called back at this delegate method.
You get [inaudible] of your files in this method.
You can use them directly.
And, [inaudible] single URL, because there's a property you can set in the Picker to let your customer choose multiple files at once.
So, let's go ahead and add a Document Picker to our demo app, Particles, from last year.
This is the app [inaudible] last year.
It is based on the Document Browser to let me choose a file to open.
As you can see, I have Recents, I have Tags, I have Search, I have Browse to list all my sources.
All of this comes for free.
Now, I can go ahead and open this file, and I can tweak this nice particle system.
Now, my customers love this app.
But, they would like to make the particles a little nicer.
So, they've asked the designers to design some better-looking particle images, and the designers have shared these images over iCloud.
So, how do we get these images to customize them?
What we're going to do, is add a Choose Image button in the navigation bar here to pick a file from iCloud, and customize these particles.
So, you can open your storyboard, and here I am [inaudible] the controller.
I'm going to drag a new bar button item to that editor.
And, I'm going to animate Choose Image.
[inaudible] Choose Image.
OK. Now, I get to write some code to present to the document picker of the controller.
So, I can drag an action from my button to the source code, and I agree to call it Choose Image, and [inaudible].
And, now I have twice my code.
So, let me display this in a bigger window.
Here I am in my chooseImage method.
I'm going first to create a Document Picker controller.
And, I specify the type of files I want my customers to choose.
So, here this is UTTypeImage, and the mode.
I'm using .import here because I want to embed the particle image in my document.
But, in many cases, you will use [inaudible] here instead.
You set your document picker delegate, and you present it.
When the Document Picker gets invoked, and the file is chosen, it going to call you back.
So, we need to implement the document picker [inaudible] at method.
I don't know if you noticed, but I have not set a property to choose document files.
So, I'm going to check I have only one URL here.
Get the first URL, and create an image from it.
And, set it in our particle system, which is [inaudible].
Let's run this again.
It [inaudible] my app and will open my simulator shortly.
So, here I am.
I am in my simulator.
I can open my file.
And, I have this new Choose Image button in my navigation bar.
I can tap it, and my Document Picker comes up.
And, as you see, again, we have all the pictures of the Files app.
We can search our files, you have Tags.
You can browse.
All of this comes for free.
Now, my particle image is [inaudible] shared to me over iCloud, so they show up in [inaudible].
And, again, use this little star image here.
Pick it, and my particles are little stars.
[ Applause ]
This was easy.
And, when you are back at work, you will be able to add a Document Picker to your app in no time.
It simply has very little code, and does not depend on any third-party library.
Your customers simply get access to their files, no matter where they are stored.
Now, you noticed that during the demo, we have again talked about file types.
And, many among you probably don't know what these are.
So, let's talk about file types.
Document Types let the system know which files your application knows how to handle.
And, they're important because they let iOS open your app when the file is tapped in the Files app.
They also let it show your app in the Share sheet.
And, finally it lets iOS choose the proper icon for your documents.
So, if I configure my types properly, and if I want to [inaudible] extension, I'm going to see this when browsing particles files in the Files app.
If I don't, I'm going to see this instead, which is not too good, and my customers won't be able to open my files from the Files app.
So, let's configure this together.
There are two steps when you want to configure document types.
You need to declare the type first, if it is not declared by iOS already, and then you need to claim it to tell iOS you can view or edit files of this type.
Let's start with type declaration.
The first question you need to ask yourself is, do you need to declare it?
Because in most cases, you'll be dealing with common file types, such as videos, images, PDFs, presentations, spreadsheets.
If that is the case, iOS most likely already declared this for you.
And, to know if this is the case, you can check out the documentation at this short URL.
If that is the case, great, you do not have anything to do, and you can jump to claiming the type.
The other common case, is when you wrote an app which defines its own file format.
You invented your own file format, and you get to define what that type is.
Then you should declare your type as exported, which tells iOS you are the authority for this file type.
This is a situation I'm in, in the Files app in the Particles app, sorry.
My particles file format is my own.
So, I can open Xcode to configure this type.
And, in this exported UI section, which lets me edit my info.plist, I specify the type identifier, which is a [inaudible] string that I choose.
So, [inaudible] comes the example that [inaudible] sample code, the particles, and I need to declare a list of parent types in the Conforms To field.
What are parent types?
Well, types form a tree, which we call the [inaudible] tree, and you can think of it like a [inaudible], like Swift.
For example, JPEG images and HEIF images are both kinds of images.
And, .image conforms to our root type for user-created, or user-visible, documents, which is called public.content.
Now, public.content has other children, like, for example, public.spreadsheet.
You can find this list of types in the documentation I pointed to earlier.
Now, we need to find a spot in this tree for my type, Particles.
Since the particle system is not a common file category, there is no [inaudible] category for me.
So, I can't just make it conform to public.content directly.
And, I need to conform to public.content either directly, or indirectly through public.spreadsheet or .image if I want my files to show up in Recents and in Search.
Then you have a second tree, which we call the physical tree, which lets iOS know how the files are represented on-disk.
And, here this is much simpler, because you only have two choices.
In most cases, you will be dealing with a single file on disk for your document.
If you need to group multiple resources together, and you have the file package, you're going to use com.apple.package.
But, in most cases, you have a single file disk, so it's public.data.
This is because I am in with particles, so I'm going to conform to public.data.
Now, because this is a tree, .data and .package both iterate from our root type from the physical hierarchy, which is public.item.
But, you don't care about this, you just need to choose between .data and .package.
Therefore, you have two parents, public.data and public.content.
So, in my Xcode UI, I'm going to write, Conforms To public.data, public.content.
The last thing I need to do is tell iOS which file extensions are associated with my type.
This is how iOS will know that .particles files are of the type [inaudible] defined.
To do this, I add a UTType classification property to my [inaudible] properties.
In this dictionary, I add a key called public.filename-extension, and [inaudible] file extension that you want to associate with your type.
So, here I have a new item, of particles.
And, with this, our declaration is done.
There's just one more thing I didn't mention.
It is if you if this was the case where we were declaring our own type.
But, you might also want to use type defined by another application.
If that is the case, you also need to declare the type so that iOS knows about it, in case that app is not [inaudible].
And, because this is an imported type declaration, this means that if iOS finds an extra definition of that type somewhere else, it will prefer that definition over yours.
This is also what you need to do if you want to use a common file type which is not declared by iOS yet.
Now, do not freak out, it is the same UI as what we've just went through, except that it is in the imported section instead of exported.
Once you have your type defined, you can claim support for it, still in your info.plist, or the Xcode UI.
To do this, you specify the type identifier that you have defined, and the only other thing that you need to do is define a rank.
And, this lets iOS know what to do when you tap on the file and multiple apps can open this file.
For this, you have three choices.
The first is if it is your own file type.
You choose "owner."
And, to be clear, this should only be used if you happen to have invented your own file type.
In most cases, you want to use "default," if you can edit files of this type, or "alternate" if you can read files of this type, but not edit them.
And a list of [inaudible], rules are different on macOS, so if [inaudible] macOS up, please check out this other short link.
When claiming support for a type, please be as specific as possible.
We have just claimed support for a very specific file type, so .particles file type.
But you can also claim support for categories, such as any image using public.image.
This is fine, but you need to be as specific as possible to make your app show up exactly what it needs to show up.
Do not claim support for [inaudible] types such as public.data or public.content, because this will make your app show up in places where your customers do not expect to see it, and it will confuse them.
So, what can you do with all of this information?
Well, first, if you have a need to access files in the cloud, you should use the Document Browser or Document Picker to access these documents.
Most cloud vendors have adopted our API's, so if you use one of these viewControllers, your customers will be able to access their files no matter where they are.
And, you do not have to write code for each cloud vendor.
If you wrote your own custom document browsing UI before iOS 11, now's a great time to switch to UIDocumentBrowserViewController.
It is packed with features it's packed with features, so please let us do the hard work, and just get all the features in your app for free.
Finally, please make sure your document types are configured in Xcode properly so that your app shows up exactly where it needs to be, and help customers find it.
And with this, I'm going to hand the stage over to my colleague Ronny.
[ Applause ]
Thank you, Thomas.
I am Rony Fadel, a software engineer on the Documents Management team.
So, Thomas has explained how easy it is to adopt a document browser and document picker API's in your app.
Now, that you've adopted these API's, we'd like to cover some best practices to make sure that your app is a well-behaved citizen on the iOS ecosystem, the day you submit it to the App Store.
So, now that we've implemented a document browser-based app, or added picker support, now we're ready finally to pick some documents.
Your app might want to access documents directly, avoiding the copies in import mode that Thomas has described, or if you want to edit your document directly.
For this you'd need to invoke the Picker in Open Mode.
In this example, we're in the Particles app, and we've created and presented a Picker in Open Mode.
We're going to pick an image file to change our particle system's image.
Once we've picked a document, we receive a callback at one of these two delegate methods.
The first one, if we're picking our document in the Browser, or the second one if we're picking it in the Picker, like our example.
We see the document here, and we see actually the Document Picker here, serving our app the URL that we've just picked.
If we attempt to access the document directly, we risk running into a permissions error.
Let's try to understand why this could happen.
As you may know, your apps on iOS are Sandbox.
The App Sandbox is a security feature, whereas every app has unrestricted access to documents in its own app container, and by default, access is restricted to documents in other containers, namely in other app containers and in cloud service containers.
So, this is a security feature that guarantees that other apps and processes don't just go snooping around in your app container, accessing your documents.
And, always make sure that if they do access them, access these documents, that is done with user consent.
So, since access to documents in other containers is restricted, how can your app gain access to these documents that your customer has picked?
What we have to do, is to extend our App Sandbox to include these documents.
Here's again the URL returned by the Browser or the Picker.
This URL has a security scoped resource attached to it.
You can think of this resource as a permissions token granted to you by the system, and accessing this token would allow your app to access this document.
We can start accessing this document using the following URL API's.
When we call startAccessingSecurityScoped Resource, your app gets access to this document, and so you can start displaying or editing the document.
And, once you're done using it, the document, you should call the stopAccessingSecurityScoped Resource API on that URL.
And, as you can see here, access is again restricted to that document.
So, here's a simple recipe to guarantee that you will always interact successfully with Sandbox documents.
We walked through this example where we make these calls.
First, we make the startAccessing call on that URL, and so we can start interacting with that document.
And, you notice in the defer block, we make the stopAccessing call once we're done using the document.
You notice that these calls are balanced, and that we only call stopAccessing if startAccessing returns "true."
We keep resource access time as small as possible, because when we make this startAccessing call, we consume limited system resources, reserved just for your app.
And so, we need to relinquish these resources once we're done using that document to make sure that we can access additional documents within our process.
If you know for sure that this document exists inside of your app container, you do not need to make these calls.
But, in case of doubt, make these calls.
If they're not actually needed, they'll simply be a no-op.
Great. Now, we know how to gain access to our documents.
We can go ahead and pick that document, like the particle image in our example.
And, start accessing it.
As you can see here, the cloud service that is hosting this document, as well as other apps also can access this document, and sometimes concurrently with your app.
What we need here is a system-wide mechanism to make sure that access to this document is always coordinated, so that processes don't go stepping on each other's feet, accessing, reading, and writing to this document.
On iOS, this mechanism is called file coordination, and it is exposed via the NSFileCoordinator and NSFilePresenter API's.
It acts as a system-wide multiple reader/single writer lock, and it's also the way for your app to instruct the system to download this document if it's not available locally.
Because as you may know, a lot of these documents could be in the cloud, and not on the device.
So, you might find yourself writing a lot of boilerplate and error-prone code to handle sandboxing, to handle file coordination.
If you're simply interested in displaying and editing your documents, the solution is much simpler.
And, on iOS, it comes in the form of UIDocument.
UIDocument has been available since iOS 5.
It is the recommended way for your app to display and edit documents.
It handles sandboxing for you, so there's no need to make the start- and stopAccessing calls.
And, it handles file coordination for you.
So, there's no need for you to manually coordinate access to these documents.
For more information on file coordination and UIDocument, we invite you to check out the "Building Document-Based Apps" session from WWDC 2015, which covers these topics in great detail.
Alright. We can now access our documents, and we are sure to read and write to them in a consistent state.
We can edit our particle system.
And now, what we're going to do is just switch apps for just a second, check out the WWDC webpage, and just jump back to our app.
Hmm. As you can see here, we were in the editor, but now we went back to the browser.
Your customer always expects to be brought back to where they were when they were using your app.
Let's try to understand what happened in our previous example.
Here's a diagram of our app's lifecycle.
We started off in the foreground while we were editing the app particle system, and we then were taken to the background when we used the App Switcher to switch to Safari.
The system suspended our app while it was in the background.
It turns out that at the time, our system was under some memory pressure, and so the system terminated our app.
When we used the App Switcher to switch back to our app, our app was relaunched.
What we failed to do here was restore the UI state.
And, that time was a good time to restore the UI state, to bring back our customer to where they were.
So, how do we implement state restoration?
A simple and easy way would be to persist the URL we've received from the Document Browser, or the Document Picker, and restore it at app relaunch.
That wouldn't work though, for two reasons.
First, the document that the URL points to could have been moved or renamed.
And so, we'd end up with a broken link at app relaunch.
And second, the security scoped resource that is attached to our URL is not encoded when that URL is persistent.
And so, when we relaunch our app, we again lose access to this document, even if that document wasn't moved or renamed.
The correct solution is to use a security scoped bookmark, that we get from our URL.
And, as you can see, the bookmark correctly references the document, even if it has been moved or renamed.
To save the security scoped bookmark, we must first get it from the URL, using the bookmarkData API on the URL.
And, we will then persist it to disk.
Once our app is relaunched, we can restore the original URL using the URL resulting bookmarkData call.
Alright. Now that we have all the ingredients to save and restore UI state, let's jump to a quick demo to see it in action.
So, here we are in the simulator, running the Particles app as seen previously.
And, what we're going to do is just take our app to the background.
And now, we are going to simulate the fact that the system is killing our app, by killing it in Xcode.
If we launch our app again, we see that we jump back to the browser.
So, now what we're going to do is implement state preservation and restoration, to be able to jump back to where we were.
So, I'll move to Xcode.
First of all, in our app delegate, we'll declare to our app that we're interested in state preservation, and then restoration.
And, to do that we first return "true" in application shouldSaveApplicationState.
And also, return "true" in application shouldRestoreApplicationState.
Second, we'll go to our storyboard, and give our DocumentBrowserViewController subclass a restoration ID, so that the system restores this object.
And in this example, we'll simply use the storyboard ID.
Next, we're going to implement state preservation and restoration in this documentBrowserViewController subclass.
So, first I start by implementing encodeRestorableState.
We get the editorViewController, if it exists, and get the document URL from it.
Once we have that URL I'm going to make this a bit bigger.
Once we have this URL, we start accessing it to extend our Sandbox as described previously.
And, the defer block, we stop accessing once we are done using it.
If we can start accessing this document, we simply create a bookmarkData block from this document, and encode it.
And, finally, we don't forget to call super.
Alright. Now that we know how to encode our restorable state, we'll implement restorable state decoding.
And, to do this, we start implementing decodeRestorableState.
And, we'll do the inverse steps.
So, first we get the bookmarkData from the coder.
And, if it exists, create that document URL using the URL resolvingBookmarkData call.
And, we simply present the document at that URL.
And, last but not least, we don't forget to call super.
Alright. So, let's run our app.
And so, our app will now be launched in the simulator.
As you can see, we can start using our document.
And, again, going to take our app to the background.
Simulate the system killing our app.
And, we're going to relaunch our app, and as you can see here, we're back to our editor.
[ Applause ]
Awesome. We can now access documents, read and write to them without risking data corruption, and we can now even restore state and bring our customer back to where they were when they were using our app.
Even if our app was killed in the background.
So, if you open the files up, and we tap on Share in the callout menu, on documents that your app can handle, you notice that our app is now available in the Share sheet.
However, it says "Copy to" instead of "Open in."
What this means is as soon as we tap on our app icon in the Share sheet, the system will make a copy of this document, and serve this copy to our app.
And, practically this means that the customer would start editing a copy of the document.
To allow your customers to open and edit the original document that we wish to access in your app, you need to adopt an iOS feature called Open in Place.
If you do adopt Open in Place, you see the "Open in" your app in the Share sheet, instead of the previous "Copy to."
Adopting Open in Place is very simple.
If you use the document-based app Xcode template, you'll get this behavior for free, as Open in Place is already enabled by default there.
Otherwise, you'll need to add the LSSupportsOpeningDocumentInPlace to your info.plist.
Once you've declared to the system that your app handles Open in Place, we must access the document in the following UI application delegate method.
Again, if your app is document browser-based, typically in this method, you make the revealDocument call on the documentBrowserViewController.
Once the completion handler is called in this method, you present the document in the completion handler.
This is already done for you in the Xcode template.
We can now tap on our app icon in the Share sheet, and go straight to our app.
As you see here, we report progress in the UI, since the document could be in the cloud.
And, since that download could take awhile, we also support user cancellation, so we can cancel opening this document, and jump back to the browser.
Here's how you can implement progress supporting in your app.
If you call the documentBrowserViewController revealDocument API that's been described previously, you get that UI for free.
So, you'll see a loading UI on top of the icon in the browser.
Otherwise, you may opt to display your own progress UI.
If your app uses UIDocument, you should know that UIDocument conforms to progressReporting.
And so, to display your own progress UI, you simply access the progress property to display your own progress.
Alright. Our app is now awesome.
And, we're finally ready to ship it.
So, what's the takeaway today to make your apps excellent at managing documents on iOS?
Adopt UIDocument when displaying and editing documents, as it eliminates a lot of boilerplate and error-prone code.
However, if you already have document editing code that doesn't use UIDocument, adopt the start- and stopAccessing best practices to make sure that you interact successfully with Sandbox documents, or Sandbox with the app Sandbox.
And also, coordinate accesses to your documents to make sure that you read and write to them in a consistent state.
Implement state restoration to always bring back your customer to where they were, when they were using your app, even if your app is killed in the background.
Adopt Open in Place, so that your customer always edits the original document, and doesn't need to start editing copies of that document.
And, also report progress, especially in a world where most of these documents could be in the cloud, and not available locally.
So, what did we cover today?
We have shown you how easy it is to adopt the Document Browser and Document Picker API's.
Give them a try in your app today.
We learned about best practices so that our apps become excellent at managing documents, and for you cloud vendors, we talked about the new Siri shortcuts, and how they allow your app sorry, your documents that are frequently accessed to be available throughout the system for your customers.
And, we talked about the fileProvider validation tool, and gave guidelines on how to implement an effective authentication flow in your fileProviderUI extensions.
For more information about this session, check out the session webpage at the following URL.
Also make sure to check out this year's "Introduction to Siri Shortcuts" session.
Thank you for your time.
Have a great afternoon, and see you at the labs.
[ Applause ]