Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> CONRAD SHULTZ: Hi,
my name is Conrad Shultz
and I'm an engineer on
the Safari and WebKit team
and this is Session 509,
Seamless Linking to Your App.
So, if you're here at WWDC, you
almost certainly have an app
and odds are you have
a website for that app.
So a quick show of hands, how
many of you have a website
that allows users to access
some of the same content
or functionality as in your app?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or functionality as in your app?
Great. This talk is for you.
So we are going to talk about
how we can tear down the walls
between your app
and your website
and create a tight
association between them.
As an example of what we
are going to talk about,
I would like to begin
with a demo of an app
that you probably have
installed on your iPhone
or iPad right now, the WWDC app.
So here I have a message
from my colleague, Jonathan,
telling me to check
out a keynote.
And that sounds like
a good idea,
and I have the WWDC app
installed on this iPad.
And I see this is a web link
so it will probably
still open in Safari.
Let's go ahead and tap on it.
And, huh, that's pretty cool, it
took me right to the WWDC app.
Maybe you missed that.
Let's do that again.
I will go ahead and tap on back
to messages in the upper left.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I will go ahead and tap on back
to messages in the upper left.
I see this is just a
regular HTTPS link going
to Developer.Apple.com,
and I tap on it, and, boom!
Right to the WWDC app,
right to the keynote.
No ping ponging through Safari.
It's magic!
[ Applause ]
So we are going to talk
about three cool technologies
to help you tear
down those walls
between your app
and your website.
First, the magic you
just saw in the demo,
where the WWDC app
opened to the right place
when a regular link was tapped.
Next, we are going to talk
about Smart App Banners,
which allow users
to discover your app
when they visit your website.
Finally, shared web credentials,
which allows your app
to access Safari-saved passwords
and, therefore, make logging
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to access Safari-saved passwords
and, therefore, make logging
into your app a breeze
for your users.
To start us off, I would
like to invite my colleague,
Jonathan to the stage to talk
to us about linking to your app.
[ Applause ]
>> JONATHAN GRYNSPAN:
Thank you, Conrad.
Hello everyone, my name
is Jonathan Grynspan
and I'm a Core Services
Software Engineer here at Apple.
Today I would like to take
a moment to talk to you
about your app's
place in the universe.
I saw a lot of hands go up
when Conrad asked how many
of you have both an
app and a website.
And it's not surprising.
Many modern apps are more than
just what the user downloads.
They also have a
strong web presence.
Often web content
mirrors app content.
Many of you have a great website
with great functionality,
and we like how your users are
able to reach that functionality
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we like how your users are
able to reach that functionality
without even having
to install an app.
We also like when your
apps work together.
An app exists as
part of an ecosystem.
If your app, or website, needs
to access content provided
by another app, or website,
it needs to communicate
with it somehow.
For example, if you have an app
for foodies and you want to link
to a recipe, you might
want to use an app
or service, such as Yumly.
So how does your
app get to Yumly,
and how does it provide Yumly's
content correctly and quickly?
On iOS we usually
use URLs to send data
from one app to another.
So let's take a look at
how we do that today.
Many iOS apps implement what's
called a custom URL scheme.
These are a very effective tool,
because they let apps
communicate with each other
but they do have a few pitfalls.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but they do have a few pitfalls.
First off, they don't
always map to the right app,
because there is no app
that truly owns them.
Two apps can claim
the same URL scheme
and users don't really
have a good way
to say which app they mean.
Second off, if your app is
not installed, they fall flat.
The URL doesn't open and the
app needs custom code in order
to handle this fairly
common situation.
And finally, they
make protecting user's
privacy difficult.
Apps need to be able to detect
if other apps are installed
on a device, in order to
use custom URL schemes.
This means that they can sniff
out if a user has a dating app,
or a banking app,
or a politically-charged
app installed.
This is personal information,
and users do not
want to share it.
So, there has to be a
better way, but what does
that better way look like?
Well, obviously, it needs
to be just as easy to use
as custom URL schemes,
so we are still talking
about a kind of URL.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about a kind of URL.
It must have verifiable
ownership,
URLs should always
open in the right app.
There should be a strong
two-way association
between your app and your URLs.
It must have the ability
to fall back gracefully,
if your app is not installed.
The URL should still work
when a user taps on it.
Safari, and web browsers
in general, are a great way
to display rich content,
and are present
on nearly every platform,
so we'll make sure
that these links can
open in a web browser.
And it absolutely must
protect a user's privacy.
When I run an app on my
device, it has no right to know
that I also have
your app installed.
And, of course, the
links that, the --
excuse me, and, of course,
the links that you tap are
between you and your device.
There is no need for a
third party to be involved.
As Conrad showed you, web
URLs are the ideal solution
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
As Conrad showed you, web
URLs are the ideal solution
that fit all of these criteria.
You know when they
are going to open,
they work nearly everywhere,
and no third party needs
to be involved when you tap one.
Now that we have
identified web URLs
as our solution,
let's break one down.
I know you have all seen a URL
before, but if we take a look
at the components of a URL,
we'll have a better idea
of how these links
are going to work.
Here is a perfectly
normal web URL.
If you are curious, this links
to last year's WWDC
keynote video.
This is not a new URL that
we had to generate just
for this purpose, or
just for this app.
It already existed,
and you can visit it
on the Apple Developer
Connection website today.
If I open it in Safari, I expect
to see exactly the content
that you would expect, the
video and information about it.
If I - uh, I also expect to see
the same content if I open this
on a Mac, or on another platform
entirely, they are universal.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on a Mac, or on another platform
entirely, they are universal.
And thanks to universal
links, this link will open
in our WWDC app without a
web browser getting involved.
So, in order for that to work,
iOS needs to look
for a few things.
The first thing we
look at is the scheme.
We support HTTPS and HTTP URLs.
Next up is the domain,
or host name.
The domain is securely
associated with your app,
by using an SSL certificate
to sign a file that is stored
on your secure web server.
I will have more info on
that in just a moment.
After we have analyzed
the scheme and the domain,
we take a look at the path.
The path can either
match exactly,
or it can match with a prefix.
In both cases, you specify
the matches, uh, sorry,
you specify the matches and you
are in control of the situation.
This is useful if you have
content that is on your website
but is not representable
in your app yet.
If a URL does not match,
it opens in Safari just
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If a URL does not match,
it opens in Safari just
like any other link would.
If we do match a URL and we need
to - sorry, if we do match a URL
and send it to you, you
can use NS URL components
to break it down, and to
get at the information
in the URL that's useful to you.
I particularly like
using NS URL Query Item
because it makes
accessing the components
of the query super simple.
Universal links mean having your
app, not Safari, handle links
to your website, but in order to
get-- in order to open your app,
when a user taps a link to
your website, iOS needs to know
that your app should
open that link.
Your app must claim that it can
handle links from your website.
And iOS then contacts
your website, and confirms
that your site knows about
your app, and is willing
to be represented by it.
So let's get your server ready.
There are four steps
in this process.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The first step is to create
a special file called the
Apple-app-site-association file
that iOS downloads
from your web server.
This file contains specially
structured JSON data.
If you adopted Handoff
from the Web
or Shared Web Credentials last
year, this should look familiar.
The top level key here is
applinks, which is sibling
to web credentials or
activity continuation
if you already have
either of them.
The apps key is important
and should be present
with an empty array
as its value.
Under the new details key,
you will see the dictionary.
The keys for this dictionary are
your application identifiers,
which consist of your
team ID, which you can get
from the Developer portal,
followed by a period,
followed by your
bundle identifier.
If you have more than one
app, you can specify each
of them under a separate key.
The paths array tells
us what parts
of the website are
supported by your app.
If you can support your
entire website in your app,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you can support your
entire website in your app,
you only need to
include a single asterisk
like you see here, but on
day one, it's quite possible
that your app won't
support every single page
on your website.
So we have given you
the ability to specify
which pages it can handle.
As you can see, I have now
added two paths to the array.
The first is an exact match.
If a user taps a link that
goes to exactly that path,
it will open in this app.
If an entire section of
your website is supported
by your app, you can use a path
prefix, such as the second entry
in this array, to specify
that that section
will open in your app.
Notice the asterisk at
the end, which tells us
that this is a path prefix.
It's important to note that
these paths are case sensitive
and that other URL
components, such as the query
or the fragment,
are not supported.
The second step is to
procure an SSL certificate
from a recognized
certificate authority.
This is not the same certificate
that you use to sign your app
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is not the same certificate
that you use to sign your app
for the App Store it's
not generated by Apple.
We suggest that you use the
same certificate that you use
for your HTTPS server,
but it's not required.
If you have more than one domain
that you need to represent
in your app, we suggest you
consider getting what's called a
wild card certificate.
For more information on
certificate generation,
please contact your
certificate authority.
Step 3 is to sign the JSON file
you just created using your
SSL certificate.
In order to do this,
you will need
to use the openssl smime
command in terminal
on your development Mac.
These two file names
are important.
The first one is the name of
the file that you just created,
the unsigned JSON file that's
on your development Mac.
The second must match
exactly what you see here,
apple-app-site-association.
These are your private key,
which you generated during
certificate generation,
and the certificate
that was given to you
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the certificate
that was given to you
by your certificate authority.
Once again, this is
not a certificate given
to you by Apple.
It's neither your App
Store certificate,
nor your developer
ID certificate.
There is one last
note to make here,
if you have an intermediate
certificate that was given
to you by your certificate
authority, you will need
to include during signing.
The fourth and final step,
now that you have
a signed JSON file,
is to upload it to
your web server.
This goes at the
root of your server.
For example, www.example.com
/ apple-app -site-association.
It's important to
note that each app
that your domain supports may
need a separate JSON file that's
signed appropriately
for that domain.
For example, example.com and
www.example.com are distinct.
We introduced this
functionality in iOS 8,
in support of two features:
Handoff from the Web
and Shared Web Credentials.
In iOS 9, we are adding
support for universal links,
and we want to make it as
easy as possible for you
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we want to make it as
easy as possible for you
to adopt universal links in
your app as soon as possible.
So-sorry, starting
in seed 2 of iOS 9,
we will no longer require you
to sign your
apple-app-site-association file.
Simply upload the unsigned
JSON -- thank you [applause].
Thank you.
Simply upload the unsigned JSON
file with the same file name,
apple-app site-association,
to your HTTPS server,
and iOS will take
care of the rest.
Note that the signing
requirement remains in effect,
if you need to support iOS 8
for backwards compatibility.
If you are starting with iOS 9,
you do not need to
fine the file.
Now, let's talk about adoption
within your application.
You will need to modify
your application delegate,
and you will need to
adopt an entitlement.
I will show you how to do both.
First off is the
application delegate.
If you adopted Handoff last
year, this should look familiar.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you adopted Handoff last
year, this should look familiar.
This method is sent to
your application delegate,
when a user activity is
delivered to your application.
User activity objects
- excuse me -
user activity objects have a
web page URL property that,
in the case of this feature,
is always an HTTPS or HTTP URL,
it's never nil for this feature.
The activity type, in the
case of universal links,
is always NS User
Activity Type Browsing Web.
Once you have confirmed that the
activity type matches what you
are expecting, you
can break down the URL
from the web page URL using
the NSURLComponents class.
Just like with custom URL
schemes, it's possible
that the URL doesn't
represent anything in your app,
or it represents outdated
or malformed content.
If that occurs, you should
detect it and fail gracefully.
Now, gracefully here,
is app specific.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It may be appropriate for you
to present an alert to the use,
explaining what went wrong,
or it may be a better choice
for you to open the link
in Safari, which you can do
from your app, by calling
UI Application Open URL.
The most important thing
to take away from this,
is that users are
not left staring
at a blank View Controller.
Once your application delegate
has been updated, you will need
to update your app's
entitlements.
This is easy with XCode.
Navigate to your
projects settings,
and to the configurations,
sorry,
the capabilities tab there,
and select associated domains.
You will want to add an
entry for each domain
that your app supports: app
links, followed by a colon,
followed by the domain name.
Once again, every domain
that your app supports
needs a separate entry here,
they are distinct.
Example.com and www.example.com
need separate entries,
as you see here.
I will show you how
this all comes
to together in just a moment.
But first I would like to review
a couple of best practices.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But first I would like to review
a couple of best practices.
As with all content coming
from outside your app,
data may be malformed and
you may need to validate it.
If it is, that doesn't mean
that you have made a mistake,
but it does mean
that you will want
to fail gracefully
when it occurs.
Once you have a URL to
process, you should keep in mind
that HTTP has caveats on iOS 9
for the sake of user security
and privacy, if you transport
data using, for instance,
NSURLSession, you should
always be using HTTPS.
If you need to use
unencrypted HTTP in your app,
you should review Session 711,
Networking with NSURLSession,
which covers an important new
networking technology called App
Transport Security.
Now, let's take a look at how
this all fits together in XCode.
I will be showing you code
from the WWDC app that's
available on the App Store.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from the WWDC app that's
available on the App Store.
So I have here the WWDC project,
and I have created a new
extension that's going
to house the code we
are looking at today.
This extension is on my
application delegate class
and the first thing I'm going
to do is add the
application delegate method
that we discussed.
Now, again, if you adopted
Handoff last year this is the
same delegate method.
You'll just need to extend it to
support this new functionality.
The parameter we
are interested in,
is the user activity parameter,
which contains information
on what the user is doing,
which in this case is
navigating from a website.
We are interested
in the activity type
and the web page URL.
For our purposes, the activity
type is always NSUser activity
type BrowsingWeb.
However, if your app supports
user activities coming
from other sources, such as
Handoff, then you will need
to check the activity
type as I have done here.
Because it's NSUser
activity type BrowsingWeb,
I know there is a web page
URL and that it's not nil,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I know there is a web page
URL and that it's not nil,
so I have used an
explicit unwrap
of the web page zero property
to get the URL from it.
I then send it to this
function, present URL,
which is responsible for
breaking down the URL
and delivering it to
the user interface
so that the user can see it.
The signature of this function
is fairly straight forward.
It takes a single URL as
input, and returns a Boolean,
saying whether or not we
were able to handle the URL.
Now, the body of the method
is a little bit more complex,
but I will walk you
through it line by line.
The first thing we do is create
an instance of NSURL Components.
This class, as I said before,
breaks down the URL for you
and allows you to access
the individual parts of it,
without you having to
build your own parser.
Once we have that object, we
extract a few components from it
that we are interested in here.
For the WWDC app, we are
interested in the host
and the path components.
Now, the WWDC app can
handle URLs coming from more
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, the WWDC app can
handle URLs coming from more
than one domain, so I want to
check the domain to make sure
that it's what I'm expecting,
so I have got a switch
statement here,
with a case of
developer.apple.com,
which is the URL that Conrad
showed you earlier, or sorry,
the host name for that URL.
Once I have matched that,
I want to match the path,
and I use a switch statement,
which is very powerful in Swift,
to gather all of the components
at once, and compare them
in a single line,
s/videos,/WWDC,
something that may
or may not be a year.
I want to take a
look at that value,
which is a string right now,
and turn it into an Int.
So I cast it with the Int
initializer, excuse me,
and I also gather
the session number,
which in this case
would be Session 509.
In the case of the
example Conrad showed you,
it was Session 101.
Now, this Find Session method I
will show you in just a second.
If those components
have matched,
then I want to present
it to the user,
but I need to validate the input
first because it's possible,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but I need to validate the input
first because it's possible,
it's possible that it isn't in
a range that makes any sense.
For instance, a year
before Apple was founded
or a session number
in the millions.
So I take the year in
session, and compare them
against two ranges, 2011 to
2015 for the year, 100 to 10,000
for the session number.
And if it's in those
ranges, then it looks
like something that's valid
that we can present to the user.
So we proceed to present it.
Now, I mentioned this Find
Session method which I'm going
to show you right now.
There we are.
And this is specific to our app.
It's unlikely you will
have this exact same code,
so I'm not going to go
into too much detail here,
but the idea is that the data
that's coming in may come
from more than one source, so
we want to check all of them.
The first thing we look at is
the fragment, which in the case
of URLs from 2014 and before,
contained the session ID,
and then if that didn't contain
the session ID, we take a look
at the query which
we have broken apart
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
at the query which
we have broken apart
with NSURL query item.
In this case the query item's
property is already populated
for us.
We iterate over,
and we find the one
that either matches
ID, or instance.
Either one may contain
the session number for us.
Now, I'm almost done
with the code here,
but there is something missing.
There is a lot of
return falses here.
There is a lot of cases where we
weren't able to handle the URL.
And, again, that's okay
because we may get invalid input
from time to time, but up here
in my application delegate,
I'm not doing anything
with that return value,
and if I get a URL
that's clearly invalid,
the user is not going
to see anything.
The WWDC Apple opened,
and they will be presented
with a blank View Controller,
which is exactly what
we want to avoid.
So we are going to
fail gracefully
and it's very, very
easy to do that.
In this case, if present
URL returns false,
then I know that I didn't
present anything to the user,
and I pass the URL back
to Safari using UIApplication
openURL.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Those are all of the code
changes you need to adopt this.
If you have already got
code for custom URL schemes,
it's quite likely it
will look very similar
to what we have here.
Now, I'd like to show you what
this app looked like before
and after we added this
code, but before I do that,
I need to add an entitlement.
So I go to my Project Settings,
I select the Capabilities tab,
and I select Associated Domains.
I'm going to add a
single entry here,
because we are only working
with a single domain today,
but once again, if you have more
than one domain, example.com;
www.example.com, they
will need separate entries
in this entitlement.
In this case, I need
applinks:developer.apple.com.
That's it.
I'm ready to go on
my client side.
So I am going to show
you what the app looked
like before we added this.
So here I have got my
iPad, and this has a copy
of the WWDC app installed
before we added, sorry,
before we added universal
links to it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
before we added universal
links to it.
And I'm going to go to the
same text message, sorry,
the same iMessage I
sent Conrad earlier.
It's exactly the same
message, but when I tap it
because I haven't
adopted universal links,
it just opens in Safari.
Safari is a great app and it can
show me some fantastic content,
and in particular, it doesn't
give me all the options
that I can get from the app.
I can watch the video in
both the app and Safari, but,
I can also provide feedback from
the app, or, make it a favorite
to watch later, I can even
download it for offline viewing.
So, as I showed you, we
have this now in our app,
in the app you have in
your hands right now,
and that looks a
little bit like this.
So, once more, this is the URL
that I sent Conrad earlier,
and I tap it, and just as
before, it opens the keynote
and I can add it
to my favorites,
I can watch the video,
download it, and so forth.
And that is pretty
much everything we had
to do [applause].
Thank you.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So before I hand the
remote back to Conrad,
I would like to thank you for
coming, and I look forward
to seeing what all
of you are going
to create using universal
links in iOS 9.
Thank you.
[ Applause ]
>> CONRAD SHULTZ: Great.
Thank you Jonathan.
So by adopting universal
links you will give all
of your users the best
possible user experience.
For users who have your app
installed on your iPhone
or iPad, links to your
website will open immediately
in your app without
any distracting flashes
through Safari.
You no longer have to write
JavaScript on your website
to detect if your
app is installed,
or try to defect it it's
installed, and launch the app
on behalf of the user.
If a user does not have
your app installed,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If a user does not have
your app installed,
your links will still
seamlessly open in Safari.
And for the same reason, your
links will still just work
on the Mac or even
on other platforms.
Now, because this is all handled
locally on the user's device,
there are no wasteful
extra round trips
out to the user's web server
or out to your web server.
And, of course, this also means
the neither Apple nor any other
third party can track
what your users are doing.
So we have talked a
little, or, we have talked
about how these links will
take the user to your website
if they don't have
your app installed.
Once there, many of
you probably want
to help your user discover
and install your app.
And ILS has a technology
that can help
with that called
Smart App Banners.
Let's spend just a
couple of minutes talking
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's spend just a
couple of minutes talking
about Smart App Banners which is
also about the time it will take
for you to adopt them.
So what are Smart App Banners?
They are unobtrusive UI
elements that help route users
to your app, and which are
presented automatically
by Safari on iOS.
If a user doesn't have your app
installed, the banner will offer
to launch the App Store so
that the user can download it.
If the user does have your app
installed, the banner will offer
to launch the app for the user.
Smart App Banners are trivial
to add to your website.
And new with iOS 9's
app search feature,
Smart App Banners will be used
by Apple to help index your app
and its content, which
increases the likelihood
of the user finding and
installing your app.
Now, some of you might
use custom URL schemes
to launch the user into
your app from your website.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to launch the user into
your app from your website.
This will still work,
but it's not recommended.
And there is no guarantee
that the user experience
with custom URL schemes will
remain the same in the future.
Smart App Banners afford the
preferred user experience.
So to adopt Smart App
Banners, all you need
to do is add one line of HTML
to your website's head section.
The apple-itunes-app meta tag
will tell Safari that you want
to install, or display,
a Smart App Banner.
The content attribute
must include your app ID,
which is used to route the
user to the correct app.
You can obtain your app ID
using the convenient iTunes
link maker.
The app argument should
include the URL of the page
that is currently
being displayed.
This is for a couple of reasons.
First, this allows you
to customize the view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First, this allows you
to customize the view
that you show to the user.
And it's passed to your
application open URL source
application annotation method.
Second, it is, it
helps make sure
that app search recognizes
your site as more
than just a landing page.
And for more information on
this point, I would refer you
to the Introducing
Search API session.
You can find the video of it.
It was held yesterday.
Finally, note the Smart
App Banners will not appear
in the iOS simulator, so be sure
that you test on
a physical device.
Once you have adopted
Smart App Banners,
and once your app can handle
links to your website,
you have a really
cool opportunity
to simplify your website.
It no longer needs to
be a promotional vehicle
for your app.
It can instead focus on
presenting your content
in the best manner possible.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the best manner possible.
You no longer need to be in the
business of displaying banners
or splash screens,
or writing code
to handle custom URL schemes.
Your website can now be simpler
to use and simpler to write.
Okay. So we have talked
a fair bit about how
to get users into your app.
Once there, many of them
are going to have to log
in to your service,
for it to be useful.
If that happens, they
might see a screen
like this, a log-in form.
This is a frustrating
moment for your users.
They probably don't remember
their credentials even though
they might have logged into
your site many times in Safari.
They don't want, or don't know,
how to look their passwords up.
This is precisely the moment
when the user might
just abandon ship,
leave your app, maybe
even delete it.
But what if instead you could
present a list of credentials
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But what if instead you could
present a list of credentials
for the user to select?
That would turn this into this.
A simple picker that
allows the user to choose
from passwords they have
previously saved in Safari.
Well, the technology to do
this was introduced in iOS 8
and it's called Shared
Web Credentials.
Shared Web Credentials
allow your app
to access Safari's
saved passwords
and thereby eliminate
the headache for users,
of r having to remember
their passwords
in different contexts
on different devices.
How does this work?
Well, when Safari on either iOS,
or OS X sees a user logging in,
or filling out an
account creation form,
it can help the user in
several different ways.
Specifically, Safari can
offer to save passwords
on the user's behalf
in the keychain.
It can sync those
passwords to all
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It can sync those
passwords to all
of the users' devices
using iCloud Keychain,
so they are always available
on the user's iPhone,
iPad, and Macs.
It can suggest
cryptographically-strong
passwords for the
user, and of course,
it can autofill those
passwords on the user's behalf,
when the user goes to log in.
And with the Shared
Web Credentials API,
it can also prevent users
from being stuck on your app
when they go to log in.
To adopt Shared Web Credentials,
there are two parts.
First, you need to
establish a tight association
between your app and your
website just like we talked
about for universal links.
Second, you do need to adopt
a little API in your app,
to access the credentials
themselves.
So since shared web
credentials allows the user
to share their passwords,
we need to establish
that you control both
your app and your website.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that you control both
your app and your website.
Just like we did when
we allowed your app
to handle links to your website.
Your server tells us to trust
your app by a simple addition
to the
apple-app-site-association file
that Jonathan discussed.
Specifically, all you need to
do is add a top level dictionary
under the web credentials key,
with a key of apps, and an array
of app IDs, that your server,
your website trusts
to share credentials.
Your app also needs to tell
us to trust your website.
And this is accomplished
by adding, a,
one or more web credentials
entries
to the associated-domains
entitlement
that we talked about earlier.
And you can also do this using
XCode's project inspector
as Jonathan showed in the demo.
Okay. So now let's talk about
adopting the API in your app.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Okay. So now let's talk about
adopting the API in your app.
A typical flow in your app
might look something like this.
First your app will check to
see if it has credentials saved
in the keychain, and if
so, use them to log in.
If not, it will ask to
access any passwords
that Safari has saved.
If those are available,
it will use those,
it will save them
locally and then log in.
If none are available, it will
present its built-in log-in UI,
to ask for credentials and then
proceed in the usual manner.
So a basic implementation
of requesting Safari's passwords
might look something like this.
The key function is
SecRequestSharedWebCredential
which takes a completion
handler,
and optionally takes domain
and user name arguments.
In the completion handler,
we check whether we
got credentials back,
and if so, use them to log in.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and if so, use them to log in.
Otherwise, we will
present the log-in UI.
Note that in both cases we
dispatch to the main queue
because there is no guarantee
that the completion handler
is called on the main queue.
So if your app allows the
user to create an account
or change their password,
you really should
update Safari's keychain
so that the next time
the user goes to log
in to your website
on, say, their Mac,
the correct password is
available to be autofilled,
and you can do that using
the SecAddSharedWebCredential
function as shown here.
The Shared Web Credentials API
also lets you generate secure
passwords using the exact
same algorithm as Safari,
using the Sec Create Shared Web
Credential Password function,
as shown here.
There are some additional
advanced features of the API,
and if you are interested
in those, I will refer you
to last year's session, Your
App, Your Website, and Safari.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we have talked
about some great tools
for giving your users
the best experience
in both your app
and your website.
First, on iOS 9 with just a
little bit of work on your part,
regular links to your website
can become universal links.
And can open your
app just as easily
as they open your website.
And iOS will insure that
your users are given the best
possible experience,
which may be your app,
or may be your website.
The days of using custom
URL schemes to route users
into your app are over.
Next, you can adopt Smart
App Banners, which will,
the first time your user
visits your website,
will help them discover
your app.
On a subsequent visits,
they will help redirect
users into your app.
And at all times, they will
help App Search index your app
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And at all times, they will
help App Search index your app
and its content, so that it
is available to your users
in both Safari and Spotlight.
Finally, by adopting
shared web credentials,
you can give your app access
to Safari's saved passwords,
and make logging into your
app a breeze for your users.
For more information on what
we have talked about today,
you can check out
our documentation.
You can ask a question
on the Dev forums,
and of course reach out to DTS.
You can also contact John Davis,
our Web Technologies Evangelist
or Jake Behrens, the App
Frameworks Evangelist.
There are several related
sessions, both this year
and last, that go more
into detail on some
of the topics we discussed.
Thank you and have a great
rest of the conference.
[ Applause ]