Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
[ Applause ]
>> Thank you.
I'm Mike Hess.
I'm a software engineer on the
iOS Apps and Frameworks team
and I'm here with Johannes
Fortmann to talk to you
about building great cloud
documents-based applications.
So here we go.
We've made some important
changes to iCloud.
First, the iCloud daemon has
been completely rewritten
on top of CloudKit.
We're calling it iCloud Drive.
If you're interested
in learning more
about CloudKit I encourage you
to attend their sessions
and labs.
Second, we've added
Windows support to iCloud.
Now your users with
Windows devices can access
and modify their documents
on their Windows devices.
Third, we've added an
iCloud folder into Finder.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Third, we've added an
iCloud folder into Finder.
Now your users can add
whatever documents they want
into their iCloud
folder in Finder
and organize them
however they see fit.
Fourth, we've added access
to this iCloud folder
from within your iOS apps.
We'll get into this
a little more later.
So what are we going
to cover here today?
We're going to start off
by talking about some
of the best practices
of accessing your
documents in the cloud.
Then we're going to move on to
talking about how to discover
and list your documents
in the cloud.
Next we're going to talk about
displaying thumbnails in your UI
when you're listing your
documents in the cloud.
Then we're going to talk about
accessing documents from outside
of your apps container such
as the shared iCloud folder.
And finally we're going to talk
about providing document storage
to other applications
from within your app.
So what is a document anyways?
We're going to define
a document here
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We're going to define
a document here
as a single standalone entity
and it's understood by the user
as a single standalone entity.
A user might want to modify it
or give it a name
that's meaningful to them
or send it via email to one of
their friends or colleagues.
There are some documents
which we all sort
of understand are documents.
A keynote document
or a numbers document
or a pages document
are clearly documents.
But we're also going to consider
something like a chess game
to be a document for
this presentation.
A user might want to
save the current state
of their chess game and email
it to one of their friends
so they can pick up
where they left off
against some hard AI level.
So we're going to consider a
chess game to be a document.
Now let's talk about dealing
with your documents
in the cloud.
So it's important when you're
dealing with your documents
in the cloud to use
file coordination.
There are several
reasons for this,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There are several
reasons for this,
but one of the main ones
is to avoid data loss.
You may have the simplest
single-threaded application
in the world, and you may think
that you're the only one reading
from or writing to
your documents,
but once you add the iCloud data
into the mix that's
no longer the case
so use file coordination.
Let's take a quick
example of this.
Say your app is doing
proper file coordination.
You'll write your
changes to disk,
the iCloud Drive daemon
will pick up those changes
and push them up to
the cloud and down
to all the other users' devices.
Everything's working
properly here.
That's what you want
to have happen.
Now let's say you're not using
proper file coordination.
You may be writing
your changes to disk,
but iCloud Drive may also be
writing changes at the same time
for that same document.
This could result in
a corrupt document
which the iCloud Drive daemon
will again push up to the cloud
and down to the other
users' devices which results
in data loss everywhere
so use file coordination.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in data loss everywhere
so use file coordination.
It's very important.
There's good news though.
UIDocument makes things simple.
UIDocument and NSDocument
on OS X does all the
heavy lifting for you.
It takes care of
file coordination.
It also uses background queues
to prevent the file coordination
from blocking your apps UI,
and UIDocument provides you
with several high-level APIs
for whatever use
case you might have.
Let's take a quick example
like reading a document
from disk with UIDocument.
So at the highest level
UIDocument does all
of the file coordination for you
and in addition reads
your document from disk.
If your document is a file
you'll get an NSData object
which is the contents
of your file on disk
and if the document is a package
you'll get an NSFileWrapper
object which represents
your package on disk.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
object which represents
your package on disk.
You just have to override the
LoadFromContentsofType method
and then display the contents
of the document to your users.
At a slightly lower level
UIDocument still does all
of the file coordination
for you,
but this time you would an
NSURL back which is the location
of your document on disk.
You then just have
to read the document
and display it to your users.
At the lowest level we have an
option that's really provided
only for hooking.
If you override the
openWithCompletionHandler method
you should really invoke
super and implement one
of the other two methods.
You can override
this method though
if you want some custom
application behavior
when UIDocument would be
doing the file coordination
to read the document from disk.
New in IOS 8 we have
some asynchronous file
coordination APIs.
So the existing file
coordination APIs were
completely synchronous.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That means you would have to
do your own background queuing
to prevent file coordination
from blocking your app.
That can be a little
bit tricky to do.
So we have some new
file coordinator APIs
for asynchronous
file coordination
which is the coordinateAccess
WithIntents method.
We also have a new
corresponding class
which is the NSFileAccessIntent
class
which essentially just
contains a URL and some options
for your intent of coordination.
You pass these in an array
to the
coordinateAccessWithIntents
method to do your file
coordination operations.
Let's take a quick look at
that in some simple code.
So this code might be if
I want to copy a document
from one location to another.
As you can see I
allocate a source intent
to read the document where
it currently exists on disk.
I then allocate a destination
intent for the location
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I then allocate a destination
intent for the location
that I want to copy
the document to.
I pass these to the
file coordinator method
of coordinateAccess
WithIntents and at some point
in the future my accessor
block will be called
on the queue I provide.
I then just have to do my
operation in my accessor block.
Now it's important when
you do your operation
in your accessor block to use
the URLs that are attached
to the NSFileAccessIntents
because they may have
changed while you were waiting
for your coordination.
Now let's move on to discovering
and listing your
documents in the cloud.
So the way to discovery and list
your documents in the cloud is
through the existing
NSMetadataQuery APIs.
Now in previous versions of iOS
NSMetadataQuery has been slow
to pick up your local changes
like creates, deletes
and renames.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
like creates, deletes
and renames.
Let's take a quick look at this.
So let's say you have your app,
you have a couple of documents
in your apps container,
you also have a couple
of NSMetadata items from your
NSMetadataQuery which correspond
to those documents on disk.
Now let's say your app
creates a new document on disk.
There might be a long delay
before NSMetadataQuery updates
and gives you a new
NSMetadata item corresponding
to that newly created
local document.
New in iOS 8 NSMetadataQuery
is easier
to use directly with stitching.
Let's take a look at that.
Now let's say your app creates
this new document on disk
and is using proper
file coordination.
This only works if you create
the document using proper
file coordination.
We actually have a hook in
your file coordination access
which will update the
NSMetadataQuery quickly
and automatically to
create a new NSMetadata item
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and automatically to
create a new NSMetadata item
to update your app.
That means that you no
longer need two data sources
to show your app's UI
one from local changes
and one for cloud changes.
You just need NSMetadataQuery
[applause].
Thank you.
Also, NSMetadataQuery can
list non-local documents.
You may want to display
some file system attributes
about those documents
though to display in your UI
when you're listing
your documents.
We have a new NSURL API for you
which will let you get
file system attributes
about those documents which may
or may not have their
content available locally.
The way to do this is
with the NSURL method,
getPromisedItem
ResourceValue:forKey.
If you want more than one file
system attribute we also have a
bulk method which is
the promisedItemResource
ValuesForKeys.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You don't need to be
under file coordination
when using these methods
for listing your documents.
Also, if you are under file
coordination we have some new
file coordinator flags
for dealing with metadata.
The key difference with these
methods is that the content
with these flags that you pass
through your file coordinator is
that the content of the
documents does not need
to be available locally when
you are doing file coordination
using these flags.
Now let's move onto
document thumbnails.
So we think the best
user experience
when you're listing your
documents in your app is
to show document previews.
This gives your user
more context
so that they can
quickly identify
which document is meaningful
to them at that point in time.
As you can see in this pages
app we have document previews
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
As you can see in this pages
app we have document previews
which lets your user
quickly identify
which document is which.
Now it was possible to show
document previews previously,
but it required a
custom implementation.
New in iOS 8 we have some new
file system attributes keys
for you to display
thumbnails in your app.
The main way to do this is
with the NSURLThumbnail
DictionaryKey.
If you call this on
your document using the
getPromisedItem ResourceValue
:forKey method you'll get a
dictionary which
contains your thumbnails
which you can display
on your UI.
The only key in this dictionary
right now is the NSThumbnail
2024x1024SizeKey which
corresponds to the UIImage
or NSImage which you can
then just display in your UI.
Now onto saving document
thumbnails.
So the easiest way
to save thumbnails is
through UIDocument.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you override the
fileAttributesTo WriteToURL
:forSaveOperation method and
have it generate a UIImage
which is your thumbnail
and return it UIDocument
will automatically write the
thumbnail to disk for you
and then the iCloud daemon
will go ahead and pick
up those changes and push
them up to the cloud.
Alternatively, if you're not
using UIDocument you can save
your thumbnails manually using
the existing NSURLsetResource
Value:forKey method,
but you should really be
under file coordination
when you invoke this method.
On OS X thumbnails are actually
generated for you automatically.
However, if you have a custom
document format you'll need
to let Quick Look know
how to display thumbnails
for your documents, so you'll
need a Quick Look plug-in
to generate your thumbnails.
Now let's move onto to
discovery documents outside
of your apps container.
Now in previous version
of iOS it's been difficult
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now in previous version
of iOS it's been difficult
for your users to
access documents outside
of your apps container
from within your app.
Let's take a look at how they
might do this previously.
So let's say you have your app.
You have direct access
to all the documents
in your app's container.
There's no problem there.
But let's say your user wants
to open say document three
from within your app.
How might they go
about doing this?
Well, one way they might
do this is they would have
to launch the other app,
then using the UIDocument
interaction controller make a
copy of the document from
the other apps container
into your app's local container.
Only then could they read the
document from within your app.
We think a better
user experience is
if your app can just
access those documents
in the other apps
container directly.
So if you have your app again
if you can just open those
documents directly the user
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if you can just open those
documents directly the user
is happy.
So we think that's a
better user experience.
New in iOS 8 there's
a way to do this
with a UIDocumentPicker
ViewController.
This allows your users to
discover documents outside
of your app's sandbox and
lets your users grant your app
permission to access
and modify the documents
that they have chosen.
Now to have your
apps container show
up in the document
picker you have to opt-in
by marking your container
with a NSUbiquitousContainer
IsDocumjentScopePublic
to be yes in your info P list.
I have a great new UI --
we have a great new UI here
which you can display in
your app for your users
to choose documents and
I'd like to show you
that now with a quick demo.
Okay. Let's go ahead
and launch my app.
Yeah, the app I've written.
It's a simple text editing app.
So as you can see, I'm
using NSMetadataQuery
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So as you can see, I'm
using NSMetadataQuery
to list only one document
in my container right now,
but I'm using NSMetadataQuery
without file coordination
to list my documents and
display a quick simple preview
of the documents.
Now let's go ahead and launch
up the document picker.
So this is our new
document picker UI.
As you can see there are
several containers listed here
but I also have a document which
lives in the shared icon folder
which is listed alongside
my containers.
Now I can switch
to list view here.
There's a bunch of stuff I can
do, sort by name, tag, state,
etc. Now let's go
ahead and like drill
down into this text edit
container and select a document
from the text edit container.
So now I have opened the
document which actually lives
in the text edit container.
I have not made a
copy of this document.
This document still exists in
the text edit container but now
that iOS user had granted
my access to it I can edit
and access it in the
text edit container.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and access it in the
text edit container.
Let's go ahead and
x out of this.
As you can see, now that
I've granted my app access
to this document it has now
updated in the NSMetadataQuery
and I can list it alongside
the other documents in my app.
I've also annotated
it as you can see
with a text edit name just
to tell my user that it lives
in the text edit container.
Let's take a quick
look at this in code.
So this is basically all
the code I had to write
to display the document picker.
All I have to do is allocate
the document view controller
and pass it on array
of the document types
that I'm interested in.
I have a simple text editing app
so I only passed the plain
text UTI as the documents
that my app can access.
I then just present
the view controller
and then implement these
two simple delicate methods
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then implement these
two simple delicate methods
and finally when the document --
when the user picks a document
of a given URL I just load it
and display it to my users.
It's super simple.
Now if you noticed my
app did not actually show
up in the document picker.
That's because I
haven't set my container
to be a public container yet.
Let's take just a quick
look at how to do that.
So if I open up my info P list
here, drill down into this.
As you can see my document
scope is set to be not public.
All I have to do is set this TS
and then bump the
bundled version
so that the document picker
knows that I have made a change
to my info P list and then
my app will be displayed
in the document picker so
that other apps can get access
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the document picker so
that other apps can get access
to my documents.
All right.
So a quick summary.
We've just shown
you how easy it is
to display the document
picker inside your app
and how easy it is for users
to grant your app access
to documents in other
apps' containers
such as the shared icon folder.
We've also shown you how easy it
is to make your containers show
up in the UIDocumentPicker just
by setting a flag to be yes
and then bumping
your bundled version.
With that I would like to
Johannes Fortmann to the stage
who is going to talk
to you about some
of the key principals
behind the document picker.
Please welcome Johannes
to the stage [applause].
>> Thank you Mike.
Hi, I'm Johannes from the UIKit
team and I would like to talk
to you about some of
the main differences
between external
documents and documents
that may live in your container.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that may live in your container.
As you know, your application
right now has access
to its own container only.
So you're able to read and
write the documents inside your
own container.
And as you have seen
in Mike's demonstration
for other documents what we do
is once the user has chosen this
document we save a
so-called document reference
into your container.
This document reference
will then go and point
to your external document.
To ease this new concept
into your application we
provide a few new features
and attributes on
the NSMetadataQuery.
You are probably using
the NSMetaDataQuery
with the UbiquitousDocuments
Scope right now
to list the documents that are
inside your container locally.
And even if the user has
granted your application access
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And even if the user has
granted your application access
to a document outside
of your container,
even if the user has gotten
your application access
to document outside of your
container we will still continue
to merely list the documents
that are local to your container
as long as you don't
pass a new scope
which is the UbiquitousExternal
DocumentScope.
The UbiquitousExternal
DocumentScope ensures
that you've got an NSMetadata
item that corresponds
to the file references
that the user has extended
to your application container.
Now, these new NSMetadata
items are effectively just
like the old ones.
They also have an
NSMetadata item URL key
and this NSMetadata
item URL key will point
to this NSMetadata item URL
key will point to the URL
that your document is
actually located at.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that your document is
actually located at.
That means that if your app is
using the NSMetadata item URL
key right now to
access the rile directly
that will still work even
with the document reference.
You can pass the return value
of getting this key directly
to for example a
UIDocument and use that URL
to directly access
the external document.
Now of course sometimes that
is not actually what you want
to do.
Sometimes what you're interested
in is not the actual document
backing this reference,
but rather the reference itself.
For example, you may want
to display the reference
inside a folder
in your application's
container in your UI,
or you might even
want to allow the user
to move these references
around inside their folder.
For that we provide a new key,
and this one is actually new
on iOS 8, the UbiquitousItemURL
InLocalContainerKey.
This key points to the
actual reference inside your
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This key points to the
actual reference inside your
applicant's container, so the
user can use the file that is
at this location
to move it around.
Now, there are a few other keys.
It may be useful for you
to know whether a file
that has been returned
by the NSMetadataQuery
is actually external
to your application or not --
sorry, to your application's
container.
And for that we provide the
[inaudible] document key
which will return no for
local documents and yes
for external documents.
And as you've seen in Mike's
demo he showed a little badge
or text a label to inform
the user that the document
that he's shown that popped
in there was actually not
from the local container
but rather from text edit,
and to enable you to do that we
have the container display name
key, the container display
name key is a localized key
that is fit for display
DOS and for example would
if you extended a document
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if you extended a document
from text edit would
show text edit's name.
All right.
So we've got these
document references,
but why do you even need these?
So the main reason
is for security.
We do not generally
allow any app
to access any other
app's container.
Only the document
picker can do that.
The document picker is running
out-of-process, so it's not --
it is able and has the
sufficient entitlements
to be able to list all of
the document containers.
And the only way to
get a document inside
of your application is to
use the document picker.
To that -- for that purpose we
determine a so-called security
scope URL and if you've used
the sandboxing mechanism
on OS X you may already
know this concept
of a security scope URL.
You get a NSURL which has a
tiny bit of information attached
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You get a NSURL which has a
tiny bit of information attached
to it that informs the
kernel [assumed spelling]
and of course the owning app
that in fact the owning app is
allowed to access this document
and is allowed to for
example modify it as well.
Now importantly if you
naively were to save this URL
for example you would
serialize it into a strain
and then de-serialize
it out of the strain.
You would lose this
security scope
and that is not something
you want to happen
because of course the
security scope is what you use
to access this URL.
Of course you need a way to
get back to the scope URL
and the document references
feature is providing one
of the ways to get
back to these URLs.
If you get a NSURL from the
document reference this NSURL
already has the security scope
attached so you can use it
with your document or
with the start accessing
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with your document or
with the start accessing
and stop accessing security
scope resource methods on NSURL,
but I strongly suggest
that you use UIDocument
because that does
all of this for you,
for example load
the contents off
of the file backed by this URL.
Now sometimes enumerating your
documents is not actually what
you want to get back
to the document.
For example, one thing you might
be using is state restoration
and in state restoration
of course what you want
to do is pop the user back into
the UI that they saw before.
So you instead of
enumerating files
that the user had access
previously what you want
to do is access a
very specific file.
We offer a mechanism to do that
for you, which is a bookmark.
The bookmark is also possibly
known to you if you've used it
with the sandbox on
OS X, and the bookmark
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with the sandbox on
OS X, and the bookmark
and codes the security
scope alongside the URL
so you can use the
bookmark to get back
to the security scope URL.
We offer API which
already exists.
The bookmarkDataWithOptions
API is used for by you
on a NSURL instance to create a
bookmark that you can then save.
It's basically [inaudible]
that you can then save
into a state restoration
archive for example.
And of course its counter-part
is a class method on NSURL.
The URL bears only bookmark
data which we can then use
to resolve this bookmark
into a NSURL
that has the scope attached.
All right.
Now, Mike showed you the
UIDocument picker view
controller in the
so-called open mode.
In open mode what we will do
is indeed create a bookmark
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In open mode what we will do
is indeed create a bookmark
and a corresponding
security scope URL,
hand you back the
security scope URL
and of course place
the bookmark,
the reference document
inside your app's container.
Now sometimes that is not
what you want to do actually.
For example, you may
have an application
that does not instead of opening
specific documents may also
aggregate documents, keynote
for example would be one
of these applications in which
you for example might want
to open an image from an
application to insert it
into your presentation.
You'll want to maintain
a persistent reference
to that image, but instead
want to copy this image
into your presentation
as one piece.
And we also support
a mode for that.
It's the so-called import mode.
Import mode will not
create a bookmark,
but instead we'll copy the
file to a temporary location.
You will of course
still be granted access
to this temporary location,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but the file is not persistently
referenced by your application.
After your application
terminates
for any reason we will clean
out the temporary location
and you will no longer
have access so you have
to make a copy soon after you
get your delegate call back
to actually hang
onto the document.
All right.
This is reading document
and it is
of course a very important part,
but equally as important is
of course writing document
and creating new documents.
Now as I've mentioned you
will not have general access
to containers outside of
your app's own container.
But of course you can write
into that container, so,
or possibly into a
temporary location.
So to create a new
UIDocument that is --
sorry, a new document on disk
that is exactly what
you want to do.
You can then use a special
document picker mode to move
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can then use a special
document picker mode to move
that document outside
of your app's container
but again the user chooses
where to move the document.
Let's have a quick
look at how that works.
You would of course you
already have a document,
Doc 3 in this case, and you
use the initWithURL method
on your document picker with the
URL of your existing document
to allow the user to
choose a new location.
The user now chooses a new
location and we move the file
into the new location.
We will return a
document reference to you,
so you still maintain
access to the document.
And this URL is effectively
exactly like one
that has been returned to
you by the open mechanism,
so you can enumerate this
new document preference
in your NSMetadataQuery.
Now of course sometimes that
is exactly not what you want.
You don't want the reference.
So we also have an expert
mode which allows you
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we also have an expert
mode which allows you
to forego the entire
reference thing.
In that case we will make
a copy of your document
into another app's container
and that is basically it.
Okay. Let me give a
quick summary of how
to use document management here.
We've seen that you can use the
document reference mechanism
to enumerate documents that
have been previously used by,
or granted access by the user.
We've also seen that you can use
bookmarks for state restoration
and we've also shown you quickly
how to use the import open
and export and move modes.
And all of these of course play
together to enable your user
to access all of their iCloud
documents, not merely those
that are inside your folder.
But you noticed I said all of
your iCloud documents here,
and of course your users
may have different locations
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and of course your users
may have different locations
for storing their documents.
For example, you may be
part of an enterprise
that has their own
storage management system,
and of course it would be grand
if you could grant
your users access
to those documents as well.
And for that we are
introducing a new feature,
the so-called document
provider extensions.
Now, what is a document
provider extension?
A document provider extension
is an alternate way for you
or a third party to
provide document storage.
From the host application's
perspective this works exactly
the same way as the pre-existing
iCloud storage location.
The user is able to select
one of these storage locations
from the document picker
and they can use these storage
locations in the exact same mode
so they can open documents
and move out documents
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so they can open documents
and move out documents
to the storage locations.
We implement these using two
different separate extensions,
the first of which is the
so-called document picker
extension which provides
a UI view control subclass
that is effectively free
form that the user can use
to choose a document from
your storage location or from
of course from someone
at the storage locations.
This UR document picker
subclass is displayed as part
of the document picker
view controller
so it's effectively
contained inside one
of these view controllers just
like the iCloud picker is.
There is also a separate
second extension
which is the so-called
file provider extension.
The file provider extension is
a non-UI extension which deals
with actually providing the
files, the [inaudible] cases
where you want to provide files
would be for example ensuring
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
where you want to provide files
would be for example ensuring
that a file on disk is
current, uploading a file
that has been changed by
the user, or enabling us
to identify a file,
so the user can save,
or the user's app can save a
bookmark for state restoration.
The file provider extension --
access to the file provider
extension is modulated
through file coordination which
means that all accesses that go
through file coordination will
automatically do the right thing
with regards to providing
access to the file.
This is another important case
where you absolutely must
use file coordination
or everything else --
everything will just not work.
All right.
Let's have a quick look
at how the data flow works
with a file provider
extension specifically
when reading a file from disk.
Let's say you have a host
app and this host app is used
by the user who is trying
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
by the user who is trying
to actually open a
document in this case.
So the host app through some UI
action is calling the ubiquitous
document types in mode method
on the UI document
picker view controller,
and now the document picker --
well, the user inside the
document picker selects a
third-party document
picker extension, yours.
We instantiate your
UIDocument picker extension
and send it prepare for
presentation in mode call.
Now this method is
called with the mode
that the user has
actually selected
and at this point you want
to probably display a view
controller that corresponds
to the mode that
the user has chosen.
For example, for the
open mode you would want
to display a view controller
that allows the user
to pick a specific document
and of course for the move
out mode you will want to
display a view controller
that allows them to select a
location instead of a document.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that allows them to select a
location instead of a document.
All right.
The user now goes ahead and uses
your UI to select a document
at which point after the user
has confirmed their intentions
you have to determine
which location
in the file system you want
to store this document in.
You can then call the
dismiss grant access --
the granting access to
URL method on self, well,
that is your document picker
view controller subclass,
and thereby inform us
about your intention
to actually the user
to access this URL.
The document picker will
then call the document picker
didPickDocument AtURL
method on its delegate
to inform the user app that
the user has just picked
this document.
Now what the user is
probably wanting to do is
to read the document
at this location.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to read the document
at this location.
It will use the
NSFileCoordinator methods,
for example, coordinateReading
ItemAtURL
and its file coordinator
that it should ensure
that the document
is actually present.
NSFileCoordinator will call out
to your file provider extension,
that's your tiny
non-UI extension,
with the startProvidingItemAtURL
method.
This method take a
completion call back
which you can call once
you're sure that the item
at this specific location
is actually current.
So once you call that completion
call back on -- sorry.
Once you call that completion
call back the file coordinator
will know that it is now
able to unlock the file
and it itself can call
its accessorBlock.
And now inside your
accessorBlock the user
application can use this UR
document like it sees fit,
for example using data
with contents of URL
to be able to read the file.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to be able to read the file.
Let's take a quick
look at how security
and persistent file access
works for document providers.
Unlike the iCloud
document provider,
which saves the special document
reference inside an iCloud
container the document provider
extensions don't take part
in the document reference
mechanism.
This is because of course
in this let's say we're
in an enterprise setting our
enterprise administration has
decided that they do
not want to use iCloud,
but of course we still want
this document provider extension
mechanism to still work because
our enterprise has given us an
application that can be
used to access the files
on the enterprise's file server.
So it's no good to use iCloud in
this case of course to get back
to your document preferences.
But of course the bookmark
mechanism will still work.
To that end the file provider
is able or has to be able
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
To that end the file provider
is able or has to be able
to resolve or resolve
into a file URL
and the other way around.
Now for security purposes
we have an isolation layer
that saves the state information
about which application
has been granted access
to which identifier --
inside which file provider,
and this is also something that
we use these identifiers for.
Let's have a quick look at how a
bookmark is created and resolved
by a document provider
extension.
Let's say we have our host
app and the host app is
for some reason going into
the background and just wants
to save its state it will call
the bookmarkData WithOptions
method on NSURL and NSURL
will call the persistent
IdentifierForItemAtURL method
on your file provider extension
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
IdentifierForItemAtURL method
on your file provider extension
which can then return
a persistentdentifier.
This might be a database key
or it might be something
much simpler.
It depends on the actual way
that your file provider is
actually accessing files.
Now at some point it will
return the personal identifier
which is just a freeform
NS string to the NSURL
and NSURL will package
that up and return it
as the opaque data block
that has the bookmark data.
At this point our user app
can go and save its state
and for example get
terminated in some way,
for example the user
reboots 35s.
Now at some point later the user
is reopening their app the user
app is doing state
restoration and in the process
of doing this is calling the URL
by resulting bookmark
data on NSURL.
We hand the identifier back to
your file provider which can
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We hand the identifier back to
your file provider which can
in the URLForItemWith
PersistentIdentifier method
and it can then resolve this
identifier into a NSURL on disk.
Now, soon after we call the
providePlaceholder AtURL method
which you can use to
provide a small placeholder
that can be used
in correspondence
with the previously discussed
getPromisedItem ResourceValueby
theUser app to merely get
Metadata on this file.
But what it can also do at this
point eagerly download the file.
We will at least ensure
that you are providing a
placeholder though.
You pass the NSURL off
the file on disk back.
The NSURL method can
now return this NSURL
and the host app can use the
getPromisedItem ResourceValue
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the host app can use the
getPromisedItem ResourceValue
to merely read metadata
or use FileCoordinator AP
on the NSURL to access the file.
Well, no matter what you
have chosen that we will
at least call you to ensure if
the user uses file coordination
in this case to load the
actual data from this document
to ensure that the file
on disk is current.
All right.
We've seen how reading
works and how getting back
to your documents works.
Let's have a quick look at
how writing files works.
In this case, the user is using,
or the host app is using
the file coordination API
to actually write data to disk.
So it would do a route
coordinated write
to the file inside your
storage apps folder.
The file is now changed inside
your storage apps folder.
At some point very soon after,
but importantly to note not
in a blocking way, so the file
coordination will have succeeded
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in a blocking way, so the file
coordination will have succeeded
by this point, we will
call itemChanged AtURL
on your file provider.
At this point your
file provider can go
and for example initiate
an upload of this file,
or at the very least mark it as
being dirty and needing upload,
so you don't accidently
overwrite it at a later point.
All right.
Let's have a quick
look at how that works.
What I've done is I've built a
very small sample project using
the template that
comes with [inaudible].
It's very nice because
it provides you
with almost everything
you need at the start.
We can use the target here
and use the application
and get extension template
for the document picker
and basically choose a
name here and it'll set
up the two different extensions.
Inside my project I just have
the two different extensions,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
one folder here for
the actual picker.
I'm doing a text
snippet picker to go
with the text display
app that Mike showed.
And inside this I
have a whole bunch
of files while are
basically, well,
classes to display some
sort of picking UI,
but the important
part is my subclass
of UIDocumentPicker
ExtensionViewController here.
And inside this subclass
the important parts are the
prepareForPresentationinMode
method, let me make this big
so you can see this, and in this
PresentationinMode method what I
want to do is basically
display a specific,
in this case I'm using a
collection view controller
to display a list of documents
and I'm displaying this.
And all of my picking
actually is not handled
by my DocumentPicker
ViewController,
but by a subclass.
Of course I use a delegate
pattern to get back
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Of course I use a delegate
pattern to get back
to my main class once the
user has picked a document
and we'll call this method here
and inside this method
all I have
to do is call the
dismissGrantingAccesstoURL
with the file URL that I've
previously written out.
Now the document file
provider here is very simple
in this case.
The interesting method for this
demo is the startProvidingItem
withURL method which I implement
to ensure that the snippet
at this URL is current and then
call the completion handler.
Let's have a quick look at
how that looks on the machine.
All right.
I've got my demo up here which
is basically since I started
from the template
just an empty app.
So instead I'm going to
pop off the document picker
and you notice I don't
even have any documents
in my iCloud account,
but when I pop
up this document picker menu
here I see a list including the
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
up this document picker menu
here I see a list including the
iCloud document picker and my
SnippetPicker, and if I pop
up the SnippetPicker what is
displayed is my SnippetPicker
view controller and I
can use that to pick any
of these documents
or Snippets in here.
So when I pick these with
the exact same sample app
that Mike showed you I'm
able to access these Snippets
from my little document
picker app.
Now when you use the
[inaudible] to try this out note
that this Snippet that the
document picker you will create
will not show up by default so
you can use the little locations
in the navigation bar of
the iCloud document picker.
It has a little more pop
out where you can enable
the Snippet picker.
All right.
Now let's switch back to slides.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Cool. To summarize the demo,
we've got an Xcode template
to get you started with the
document picker mechanism.
The document picker, or a
Document Provider will show
up right next to
the iCloud picker
if the user installs them.
And we also have
sample code available
on the session home page
that will enable you
to quickly test this out.
The sample code is basically a
little test app that we wrote
to be able to display each
of the document picker modes.
Cool. So that's Document
Providers
and that almost concludes the
session, but I have a little bit
of information for
you to inform you how
since we have this new Cloud
Drive mechanism how the
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
since we have this new Cloud
Drive mechanism how the
migration story is for that.
On iOS 8 the users can either
choose to, once it comes out,
choose to use the old
iCloud Documents mechanism,
or to migrate to iCloud Drive.
On OS X Yosemite we do
not provide the backwards
compatibility for the old
iCloud documents mechanism,
so the user has to either
choose to migrate to Cloud Drive
or they will no longer
receive the updates
across their devices.
Of course they can choose
to migrate at a later point
at which point the
upgrades resume.
And of course after
an account is migrated
to iCloud Drive only the devices
that are actually using iCloud
Drive will propagate changes
between each other.
For US developers this
is important to know
because even though the current
C Build [assumed spelling]
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because even though the current
C Build [assumed spelling]
that you have in your hands
right now is automatically using
iCloud Drive the
actual new features,
and thus you can easily test all
of this out, the new features
that we've presented in today's
presentation will only be
available if your user
is using iCloud Drive.
So you have to be aware
of this possibility
in case they have not
actually chosen to migrate.
All right.
To summarize, if you're
just taking one thing away
from today's session it would be
that you should use
file coordination
for document access.
Without using file
coordination none
of these mechanisms can work
and you will probably be
at some point experiencing
data loss on the machines
of your users, which of
course is extremely bad.
We've seen how to discover
and display files not only
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We've seen how to discover
and display files not only
in your own container, but
also using the UIDocumentPicker
which allows you to
access files outside
of your applications'
containers.
We've given a quick overview how
to use document provider
extensions to be able
to integrate your own
company's storage system
into the whole document
access mechanism.
For more information I
would like to guide you
to Dave DeLong, our App
Frameworks Evangelist
and also Jake Behrens
who is the UIKit specific
Frameworks Evangelist.
We have some neat
documentation out.
There is a brand new
iCloud for Developers guide
and we also have guides
for the Document Picker,
and of course also guides for
the extensions mechanisms.
We also have the Apple Developer
Forums where our developers hang
out and will answer questions.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Related sessions, there
was a very nice session
on introducing CloudKit.
If you're interested
in the technology behind the
new UI Cloud Drive mechanism
that powers all of this.
This session is of course
not entirely necessary
if you merely want to
store your documents
because the CloudKit mechanism
is entirely transparent
from the document
storage perspective.
We also had sessions on creating
extensions for iOS and OS X
and with that thank
you for your time
and I wish you pleasant rest
of the week and a nice bash.
[ Applause ]