WWDC2018 Session 216

Transcript

[ Music ]
[ Applause ]
>> Good morning.
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 ]
>> Hello, everyone.
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].
Connect.
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.
Hello, everyone.
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.
Thank you.
[ Applause ]