What’s New in Safari and WebKit

Safari and WebKit are continually evolving with new features, APIs, and cutting edge web standards. Learn about this year's biggest feature highlights, designed to help you create richer experiences with better performance and security — whether you are developing content for a browser or developing an app with embedded web content.

I know it's been an exciting
week filled with announcements,
features, updates, developer
tools.
My name is Shloka Kini, and I
work in developer publications,
which means-- to borrow a phrase
from Cardi B., I don't just code
now, I write docs too.

Specifically, the docs that'll
help you to write amazing
applications.
Today, I'm privileged to call
out some great features in
Safari and WebKit.
So, if you develop websites, and
want to make use of the latest
web technologies, and the latest
versions of Safari, this talk is
for you.

And, if you're a native app
developer that uses web views,
or extensions developers, this
talk is for you, too.
And, even if you're not in any
of these categories, you should
still stick around, because the
latest version of Safari has
some great features that will
improve your browsing
experience.
Now, there've been a lot-- a
lot-- of new improvements since
we last had a What's New talk.
But, today I'm going to
highlight a few that can really
help you get secure, performant
apps, and use the latest web
technologies for a rich
experience.
And, many of them you can get
for free.
So, let's kick things off with
security.

And, a few announcements.
WKWebView.
Now, I know what you're
thinking.
WKWebView has been around since
2014, so it's not technically
new.
However, it's worth mentioning
again because we are now
officially deprecating
UIWebView.
So, if you're starting a new
app, or a new project, and would
like to display web content
that's not easily put into a
native view, use the WKWebView.
And, even if you've used
UIWebView in the past, switching
might be easy for you.
It can definitely save you time
in development, if you're
developing apps for both macOS
and iOS, because WKWebView works
on both platforms.
Unlike UIWebView for iOS, and
WebView for macOS.

So, you can share a lot of code
between the two versions.
WKWebView also runs in a
completely separate process from
the rest of your app.
So, unlike UIWebView, even if
your web process is compromised,
it won't compromise your app.
If your web view has complex
content, you can't accidentally
cause your app to stall.
And, even if WKWebView crashes,
it's confined to the web view,
not the app.
WKWebView can provide security
benefits while keeping your apps
performant and reliable.
So, whether it's hard or easy,
the benefits you get using
WKWebView are worth the switch.
The next announcement involves
extensions, but extending
Safari-- I mean, it's evolved a
lot over the years.

So, let me start with a quick
recap of the history of Safari
extensions.

Now, in 2010, before we had a
platform concept of app
extensibility, we had legacy
Safari extensions.
Now, these were the Safari EXTZ
files you could build in Safari
Extensions Builder.
They could be distributed
through the Safari Extensions
Gallery, or in some unusual
cases, by developers directly.
These legacy extensions were
incredibly powerful, because
they had access to all your
browsing data, which made them
popular, especially for fraud
and malware.
We needed to create a safeguard,
so that's why we didn't just
leave it at these Legacy Safari
Extensions.

So, the next milestone in our
story came in 2014, when we
introduced app extensibility for
macOS and iOS.
App extensions, though, are a
way to extend apps, not Safari.

However, this move greatly
changed how we thought about
extensions in Apple platforms.

Here, you could clearly extend
the system while users are
interacting with other apps.

And, like apps, they could be
built in Xcode.
Because of this better
extensions model, we wanted to
apply some of these concepts
back to those legacy Safari
extensions, and at the time, the
most popular ones were
adblockers.

So, we introduced content
blockers in 2015.
Content blockers were a type of
app extension built in Xcode,
that worked on both macOS and
iOS.

They have a special architecture
that makes them fast.
So, any content blocker is
faster at blocking than any
legacy Safari extension.
They don't have the power to
slow down browsing, and they're
private, because the extensions
never see what web pages your
users visit.
And, by this point, the app
extension model offered so many
performance benefits we thought,
maybe we can bring all these
concepts back to the legacy
Safari extensions, so we can get
the best of both worlds.
An extension that extends
Safari's functionality, but also
extends your app to talk to
Safari.

So, in 2016, the modern Safari
app extensions for macOS were
introduced.

A way to extend Safari that
could be built in Xcode.
And, unlike previous extensions,
you get them through the App
Store, which means they can be
free, or you can charge for
them.
Either way, you don't have to do
your own billing.

So, compared to those legacy
extensions in 2010, content
blockers and Safari app
extensions have great benefits.
So, the best thing for you to
do, is if you have a legacy
Safari extension, switch over to
a Safari app extension.
And, if it happens to be an ad
blocker, use content blockers.
And now that we've done all this
work, what can we do about the
use of legacy Safari extensions
for fraud?
Starting with Safari 12, we're
officially blocking support for
legacy extensions distributed
outside of the Safari Extensions
Gallery.
Legacy extensions will still
work in Safari 12 as long as
they're in the Gallery.
The only exception are those
extensions using the deprecated
Can Load API, which we turn off
by default.
We'll continue to accept
submissions to the Gallery until
the end of 2018.
However, we will be coming up
with more updates in the
following year, and will
eventually transition entirely
to Safari app extensions.
So, the best thing for you to do
is learn how to develop
extensions in these two models.
And, to learn how to do that,
check out the docs, courtesy of
yours truly and Developer
Publications.
Now that we've covered the two
biggest announcements for native
developers using WebViews, and
extensions developers, the
remainder of these features are
primarily going to be about web
development.
So, let's start with subresource
integrity.

Now, as a developer, you may
serve your content over an HTTPS
connection to your user.

And, that resulting content may
also include content distributed
over a third-party server, like
a content delivery network.
Now, both connections may be
secure, both may use HTTPS,
which means you maintain the
confidentiality, authentication,
and integrity of the data
transferred.
But, what happens if that third
party itself is compromised?
It could happen.
And, in this case, while HTTPS
secures the connection, it
doesn't secure against a
compromised server.
It can modify the scripts, and
styles you serve to users if
that third-party server is
compromised.

So, how does it work?
Well, with hashing.
First, you add the integrity
property for a script or link
element in your markup.
The value for this property is a
hash that you create using a
secure hash algorithm.
When a user fetches the files,
then another hash is calculated.
The two are compared, and if
they don't match, your script
will fail to execute.
This process ensures that
scripts won't execute if they're
compromised.
Unless they match what you
intended, your scripts will not
execute.
And, to make sure you don't lose
functionality, you can also
provide a fallback to reload a
resource from your server, in
case the third-party script
fails to execute.
Now, keeping compromised
resources from executing keeps
users secure.
And, intelligent tracking
prevention can keep the browsing
experience private.
Now, I'm sure you heard about
intelligent tracking prevention
in the Keynote.
It's a Safari feature that
reduces cross-site tracking by
limiting cookies and website
data for domains with tracking
abilities.

And, in previous versions,
cookies were kept according to
two rules.

One, cookies could be used in
third-party context for 24 hours
after user interaction in a
first-party context.
And two, for 30 days of Safari
use, including that initial 24
hours, those cookies would be
kept in isolated storage before
being purged.

But, now we're tightening the
belt a little.
And, we're removing the 24-hour
general cookie access window for
domains with cross-site
tracking.

But, by default, all cookies are
kept in isolated storage, and as
developers, I know authenticated
embeds are already important to
many of your workflows and
interactions with web content.

So, how do you allow
authenticated embeds?
Using the Storage Access API.

With the Storage Access API,
every time a domain with
cross-site tracking would like
to access cookie in a
third-party context, you'll need
to request storage access.

If the user has not granted
access previously, a prompt
appears, asking the user whether
to permit cookie access or not
under this website.
By enabling users to provide
explicit consent for cookie
access, we're empowering them to
take control of their cookies,
and what websites can track,
keeping their browsing
experience more private if they
choose.
Now, next, we'll move on to
authentication with automatic
strong passwords.
Now, I'm sure you saw this in
the State of the Union and
session earlier this week.
Automatic strong passwords is a
great way to guarantee that
users will always select and
save a password that's strong
when signing up for a new
account.
And, this is good for everyone.
I mean, I like to think of
myself as someone who chooses
strong passwords, but give it a
little bit of time, and I'll
realize that password wasn't as
strong as I thought.
And, I probably used it in a
couple places.
For most developers, you won't
need to do anything to get this
feature, because heuristics will
determine if you're on a sign up
or login page.

But, to guarantee this works,
regardless of login flow, add
the AutoComplete attribute to
the appropriate input fields.
Now, the strong passwords we
choose are by default 20
characters in length, including
upper case, lower case letters,
digits and hyphens.

Now, while this was designed to
be compatible with most
services, we acknowledge that
sometimes your passwords need to
have specific requirements to be
compatible with the back-end
system.
For this reason, there is a
passwordRules attribute that you
can add to your text elements to
specify those requirements.
And, on the developers site,
there's a password validation
tool, to help you test
compatibility with automatic
strong passwords, and develop
your own password rules.
Another feature mentioned in the
State of the Union, security
code AutoFill.
Another feature most of you will
get for free.
This is one I'm going to be
making good use for, because I
find it tedious to switch
between my app and the website,
and the messages, and then find
out those numbers for the code,
and input it and try to remember
it.

So, having Safari figure out
when I have to input a security
code, and then suggesting it in
the quick type bar?
Makes this much more convenient.
And, just like before, you get
this feature for free, because
it uses heuristics, but to
ensure that these heuristics
work, and you get that quick
type suggestion, mark your input
fields with the one-time code
value in the AutoComplete
attribute.
For more details, I encourage
you to check out the Automatic
Strong Passwords and Security
Code AutoFill session online.

So, that's security.
Switch over to WKWebView, more
over to content blockers in
Safari app extensions,
subresource integrity is a
failsafe to ensure you don't
serve compromised scripts to
users, and intelligent tracking
prevention improves privacy with
the Storage Access API.
And, with automatic strong
passwords, and security code
AutoFill, you get features that
are secure and convenient for
your users.

Whew. You all still with me so
far?
OK, moving right along, let's
talk about performance features,
starting with font collections.
Now, for those of you who may
not have caught it at the top of
this talk, my name is Shloka
Kini.

And that ain't no Anglo-Saxon
name.
And so, here's my first and last
names, using the Devanagari
script in the Hindi language.
Multiple fonts, different
weights and styles, but the same
character set.
New this year, we support font
collections, WOFF 2 and TrueType
collections.
Bundling related fonts together
inside a single collection file
can eliminate duplicated tables
for character maps.

For example, one of our built-in
fonts, PingFang has an 84%
reduction of file size from
using a collection.
Font collections can
substantially reduce the size of
your font files, because the
fonts share a table for the same
character set.

Now, this next feature,
font-display, requires no change
for most developers.

Essentially if you have web
content that uses custom fonts,
if they don't display for your
user for whatever reason, by
default we leave a blank
placeholder for the text for up
to three seconds, before your
font displays, to maintain the
position of all the content on
the screen.
But, if this default behavior
isn't quite right for you, and
you want to have more control
over what happens instead of
those three seconds, you can use
the font-display descriptor.
Using different values, you can
specify another font as a
fallback, or check if the
browser has that font in the
cache.

Now, one cool trick you can use
to improve the performance of
animated images is using video.

Now, I love the colored dust
explosion background on my Mac.
It's really great, but it's
static.
I mean I want this thing to bam,
pop!
I mean, I want motion.
I want a GIF.
But, animated GIFs take much
longer to load, they use more
battery power, and give lower
performance than a video file
showing the exact same thing.
Now, in Safari, MP4 video files
are supported in image elements,
making use of Apple's built-in
support for hardware video
decoding.

My content loads faster, uses
less battery, gets better
performance, but I can also use
MP4s in the CSS background image
property.
Now, if you adopt this
technique, in the simplest way,
you could come up with a version
that isn't compatible with older
browsers.
Older browsers don't support
MP4s and image elements.

Luckily, using existing
technology, you can specify a
fallback image to display if the
MP4 doesn't work.
Now, listen up, because now
we're going to move on to event
listeners.
Yes? No. Another feature that
has some great defaults, and
some customizability in special
cases.
When any user tries to navigate
a web page with a touch screen,
they're going to need to scroll.
And, for every touch to scroll,
a touch event listener can fire,
which can interrupt scrolling
and cause it to jump a little.

Take a look at these two
examples.
Now, the one on the left is
interrupted much more than the
one on the right.
I mean, it's barely moving.

So, what's the one on the right
doing right?
It's using passive event
listeners.
By default, we enable passive
event listeners on the document,
window, and body elements, so
any touch events on these
elements indicate to the browser
to continue scrolling, and not
be interrupted waiting for the
event listeners to finish.

If there are additional elements
with event listeners that you
want to make passive, you can
set the passive property to
"true" for those event
listeners.

Essentially, without preventing
default event handling, this
flag tells the browser not to
wait for event listeners to
finish, and lets your users
continue scrolling smoothly.

Next, we move on to asynchronous
calls, with async image
decoding.

Now, typically, images are
decoded synchronously.
So, the main thread is blocked.

All the images are decoded, and
then they display.
By blocking the main thread,
this blocks user interactions.
But, with asynchronous decoding,
the operations happen in
parallel, and on a separate
thread, which means the
interactions aren't blocked.

And now, new this year, async
image decoding happens by
default on the first page load,
which can cover most cases for
web content.
However we know that some of you
may have special cases.
Say, you have a tiled map on
your webpage that loads after
the initial page load.
And, if it has lots of images,
some of the tiles may be delayed
in their display.
Or, maybe you have a carousel of
images in your app that you want
to fade into each other, but
when you try to advance the
slides, if the images are
decoded synchronously, they
might not be ready for display.
And, they abruptly switch.

But, on the right, asynchronous
decoding gives you a smoother
fade.

Now, if you want to fall into
one of these special dynamic
cases, you have two options.

One, you can add the decoding
async attribute to your images
elements in markup.

Or, you can use the JavaScript
API's HTMLImageElements.decode
method, which returns a promise,
making sure that you know when
an image can be added to the dom
without causing a decoding delay
on the next frame.
And, continuing with
asynchronous calls is support
for the Beacon API.
We know, as developers, you want
to send data on an unload event.

Perhaps to track outgoing links.
And normally, asynchronous
requests on unload are ignored,
so you're stuck using a
synchronous request, which can
stall the next page load.

However, we now support the
Beacon API.
So, as long as Safari is
running, you can send your data
to the server and forget about
it, with the guarantee that it
will be delivered.
But, you've heard me talk
enough.

I mean, I'm sure you want to see
some of these security and
performance features in action.

So, I'd like to call Jason onto
the stage to show you how they
all work.

Jason?
Hi, everyone.

My name is Jason Sandmeyer, and
I'm a developer on Apple.com.
In my free time, I enjoy doing
arts and crafts, like building
birdhouses, and I recently
started this blog to share some
of my projects and inspire
others.
I spent a lot of time picking
just the right fonts, the right
colors.
I'm pretty proud of it.

But, you know what, I don't just
pride myself on good design, I
also pride myself on providing a
good, secure, and performant
experience for my users.
So, I'm really excited about all
these new performance and
security features in WebKit and
Safari, and I really want to
take advantage of them on my own
site.
I'd love to show you how easy
that can be.
So, I have my site loaded on my
MacBook Pro here.

And-- whoa.
OK.
Dude! Jason, what did you do?
Yes, this isn't the elegant
blog I was just bragging about,
is it?
Let's see-- that's the right
URL.
You know, I think I know what
happened here.
When I first started this site,
my friends, they warned me that
the lifestyle blogging industry
can be pretty cutthroat.
Clearly, this is sabotage.

Someone's replaced my style
sheet on my content delivery
network.

But, luckily, I have a backup,
fortunately.
And, we can use subresource
integrity to add a little bit of
an extra layer of security, and
ensure this doesn't happen
again.
So, I'll start by adding the new
integrity attribute to my link
tag.
I should also mention this works
on scripts, but we're going to
make some changes later, so
we'll add that later on.
So, the value of this attribute
is the hashing algorithm that
was used to generate the
checksum for the file that I
expect my users to see.
I've already prepared a hash
with SHA256.

Next, a hyphen, and then a
base64 representation of the
hash.

Now, let's save this, go back to
our page, reload.
And, we'll see there's no
styles.
Because the hash for the
downloaded file doesn't match
the hash in the HTML.
So, Safari has blocked it from
being loaded.

Now, let's connect to my CDN.
And, here's my backup on my
desktop.

Let's drag in my backup to the
CDN, replace the compromised
file.

And now, when we reload, that
looks a lot better.
Thanks. So, with subresource
integrity, I'll be more
confident that my visitors will
see the styles and scripts that
I expect them to get.
Now, let's switch gears a little
bit and talk about some
performance improvements we can
make.

I found it insightful to know
which links are being clicked on
my site, and which ones aren't.

It helps me make more informed
design decisions.
So, I have this click handler
that reports which links are
being clicked to a server that I
control that aggregates that
data so I can take a look at it
later.
But, notice this delay when I
click on this Woodworking link
that goes to a page that
showcases other
woodworking-related sites on my
page.
I'm going to click the link now.

Took about a half a second to a
second, and this is happening
because I'm making a synchronous
request in the click handler,
which blocks Safari from
navigating to the next page.

Making a synchronous request
ensures the browser doesn't
cancel the request when
navigating to the next page.
But, this is waiting for my
server to respond, which can
take a while.
And, the thing is, I don't
really care about the response,
I just want to make sure that
that data hits my server.
So, the Beacon API is actually a
perfect replacement for this.
I'm going to start by checking
that the Beacon API is available
in the browser by looking for
the sendBeacon method on the
navigator object.

If it's not available, I'll
continue doing what I was doing
before.

Then, we can just use it.
Passing in the endpoint I want
to hit, along with the data.

Let's save that.
We'll go back, reload to get the
new script.

And now, when I click this link
you'll see it's nearly instant.
I'm going to click the link
right now.
And, there we go.
So, compared to the XML/http
request this is even less code,
and it's just as reliable.
And now, it'll be much faster
for my users to navigate around
my site.
Thanks. So, next I want to take
a look at a problem that I've
noticed is more apparent on my
iPad here.
So, I've organized each step for
building this birdhouse as a
slide in this crossfading
carousel.
Tapping the right-facing arrow
advances this to the next slide.
But, you may have noticed that
brief moment of a blank white
space where the image should be.
Let me go through a few more
slides.

Let's take a look at some of the
code for this carousel, and see
what's going on.

I think this can be a lot
smoother.
So, here's my carousel class.

I want to focus on this method
here, setCurrentSlide.
This is the method that's called
when the button is clicked to
transition to the slide at the
given index.

Because each slide isn't
immediately visible on page
load, my carousel only loads the
next slide's image when the user
taps the button to advance to
it.

The problem that we're seeing is
that the transition is happening
immediately.

It's not waiting for the image
to load.
And, after the image has loaded,
it still needs to be decoded
before it's ready to be
displayed on the screen.

So, what I really want to do is
wait until the image has been
loaded and decoded, and I'm sure
that we can show the image.
And, I can use the new decode
method on the HTML image element
to make this a lot better.
So, I have my image-- a
reference to my image element
here.
The decode method will
asynchronously decode the image,
and return a promise that
resolves when the image has been
loaded and decoded.

So, I'll just pass my transition
function in as the callback for
the promise.

Now, let's switch back to the
iPad.
And, we'll refresh to get the
new script.
And now, when I advance, you'll
see this is much smoother.

Now, finally, at the bottom of
my page, I have this animated
GIF of a bird furnishing its new
birdhouse.
This image is-- this video's
pretty large-- well, it's a GIF.

Seven-- it's roughly a little
over 7 megabytes.
And, honestly the quality isn't
that great.
But, I happen to have the
original H264-encoded MP4, and
now I can just use that directly
on my page.
So, let's go back to my HTML,
and find that image.
Here it is.
So, I can just change the
extension to point to the MP4
file.
Reload. And, now I'm using the
actual video.
The quality's a lot better, and
this is only about a megabyte.

Plus, it's a little bit longer
than the animated GIF.
And, as Shloka mentioned, this
can also be used in the source
attribute to provide a fallback
image for browsers that don't
support this.
So, that's just four of the many
new security performance
features in Safari and WebKit.
I hope you'll take advantage of
them on your own site, and I
think your users will thank you
for it.
Now, I'd like to welcome Shloka
back up on the stage to tell you
about even more new and exciting
features.

Thank you.
Thank you, Jason.

And, I had no idea it was that
brutal in the blogosphere.
You stay safe out there.

And, thank you so much for that
great demo.
To recap performance, using font
collections can reduce font file
sizes.
The font-display property lets
you have more control over what
happens with custom fonts.
Using videos in image elements
can help with performance
instead of GIFs.
Passive event listeners can
improve scrolling, and using
asynchronous calls, both with
the Beacon API, and with image
decoding keeps the main thread
from stalling.
Last, we move onto rich
experience.
Some cool new features that can
really improve your users
experience.
Starting with drag and drop.
Now, first, some general
improvements to drag and drop,
thanks to some API updates, now
you can drag and drop entire
directories of files to upload
them to the server.
No compression or zipping
required.
And, we support reading and
writing MIME types for rich
HTML, plain text, and URLs to
the system pasteboard.
And, specifically for iOS, we've
made some new updates to the
data transfer API, so now you
can customize drag and drop with
the getData and setData methods.
So, for example, if I wanted to
drag groceries into my online
grocery shopping cart, I can
customize the drag and drop
behavior.

So, dragging an image element
will drop the name of that
element and its price into my
cart.
Now, you can specify what
happens with drag and drop
behavior, which lets you
implement richer user
interactions.

Next, we move into the API
section of this talk, starting
with the Payment Request API and
Apple Pay.
So, let's talk about Apple Pay.
Apple Pay's not just a way to
pay.
It's a way to rethink electronic
payments entirely.

With Apple Pay, vendors won't
directly receive credit card
information of your customers,
which keeps them more secure.
Now, we know that many of you
have been requesting a way to
support Apple Pay using a
standard API.
And, I'm pleased to tell you, we
listened, and with collaborative
efforts, Apple Pay now works
with the W3C Payment Request
API.
So, while you have the option to
use this API, remember that to
get the benefits of Apple Pay
for you and your customers, you
will need to make a few changes.
For example, adding an Apple Pay
button to your interface, rather
than adding Apple Pay as an
extra option in existing
checkout flow.

And, at the moment there are a
few features incorporated in the
Payment Request API, like
granular error-handling,
handling cobranded cards, and
phonetic names.

Features that only appear in
Apple Pay JS.
So, if you need those specific
features for Apple Pay, use
Apple Pay JS.
The next API we're supporting is
the Service Worker API.
And, if your user's network
connection isn't ideal, maybe--
I don't know, they have poor
connectivity, or they're
completely offline, you want to
make sure that you handle that
situation gracefully.
And Service Workers can do that.

A Service Worker is registered
by a unique origin, and it can
cache offline interactions, and
intercept requests made by
scripts associated with that
origin.

Now, every page in your domain
can share the same Service
Worker instance.

So, you can have multiple tabs
open at the same time, and all
those requests will be
intercepted by the same script.
So, you can keep a persistent
store of resources.

Service Workers makes your web
page, whether its a web app, or
whether you're using SF Safari
viewController, more resilient
to variants in network
connectivity.

And, the last of the APIs is the
Fullscreen API for iPad.
Now, you can customize
fullscreen controls for the
iPad.
Any arbitrary element in Safari.

And, clicking on that elements
will bring up a complete
fullscreen experience.

Now, for videos we auto-detect
the content, and a Cancel button
appears.
And, after a short delay, if the
content is playing, the button
will disappear.
Now, if you're presenting
content that ends up being
blocked by this Cancel button,
you can use the CSS Environment
Variable fullscreen-inset-top to
avoid it.
You can also have your content
hide at the same time as the
button, by using the
fullscreen-auto-hide-delay
environment variable.

Last, a couple of cool callouts,
starting with AR.
Oh, you've heard so much about
AR at this conference so far.
And now, you can add AR models
to your UI with image
thumbnails.
So, your websites can take
advantage of the brand-new AR
Quick Look.
And, the code's fairly short.
You start with an anchor tag,
set the del attribute to "AR"
and set the HREF link to your
USDZ file, then you file format
for AR models.
You add a single child, either
an image or a picture element
containing an image of the
model.
So, the resulting image looks
like this.
In the top corner of the image,
a small icon appears, indicating
an AR model is available if you
click on the image.
It's a great way to add more
depth to the content in your
websites.
And, for more details on Quick
Look, you can check out the
session online for Integrating
Apps and Content with AR Quick
Look.
And, last, watchOS.
You can already view websites on
the MacBook, and the iPad, and
an even smaller screen with the
iPhone, a screen that can fit in
your pocket.
But, now we're going to downsize
one more time.

We've brought you websites on
watchOS.
Now, I'm personally really
excited about this one, because
I receive recipes from my mom
all the time.
I cannot cook, and I see them in
Messages and emails and now,
when I get that recipe I can see
it right there on my wrist while
I'm following along.

Now, if you use responsive
design, great.
We do all the work for you and
your websites are going to look
great on watchOS.
But, if you would like to
further optimize your webpages
for Apple Watch, there's a video
for Designing Web Content for
watchOS in the WWDC app.
Excuse me.
Designing, yes.

And now, I bet Jason's birdhouse
blog could really up the ante
with some of these great new
rich experience features.
So, I'd like to call Jason back
on the stage to show us how some
of them can be used.
Jason?
Thanks again.
So, I've been thinking about
ways to make it more fun for my
readers to get started with
their birdhouse project.
Let's switch back to the iPad.

So, I have this list of all the
supplies that my readers will
need to get started.

And, I thought it'd be
convenient if I could actually
provide them with a way to add
to their shopping list, the
things they might need, and
maybe even purchase some of
these directly from my site.
Plus, I figured I can make a
little extra cash in the
process.
So, I have the ability to drag
and drop the supplies from the
left onto this shopping list.
And, this works great now on my
iPad as well.

So, let's take a look at some of
the code that's used to achieve
this.

Doesn't actually take a lot of
code to do this.
So, for each supply, I add a
dragStart eventListener, which
stores the element's text, using
the Data Transfer API.

Then, in my drop zone, which is
my shopping list area, I have a
drop event listener, that
retrieves the previously stored
text from the Data Transfer API.
And, appends that to the
shopping list element.
Note that you do also need to
add a dragOver eventListener,
and for the area where you want
the element to be dropped, to
prevent the default event, and
indicate that a drop is allowed
on that element.
So, with very little code, I was
able to create this fun shopping
UI that works great on my Mac,
and now on my iPad as well.

So, now that I can place
supplies in my shopping list, I
need a way for my users to
actually make a purchase.
Let's take a look at how we can
provide a great Apple Pay
experience with the Payment
Request API.
So, I've already added the
necessary HTML and CSS to my
site to display an Apple Pay
button, but I've hidden it by
default.
You should only show the Apple
Pay button if the user's device
is capable of using Apple Pay.
so, let's check for that, using
the
ApplePaySession.canMakePayments
method.
If Apple Pay is available, we
can show the button.
Let's add an eventListener to
the button.

Now, inside this function is
where we'll create a new
paymentRequest instance to
initiate the transaction.
If paymentRequest isn't
available, we should consider
using Apple Pay JS instead.
Here's the constructor for the
Payment Request API.

It accepts three arguments.
We'll start by adding the
paymentMethod data object.

This contains the Apple Pay
paymentMethod identifier, along
with some options specific to
Apple Pay.
Following that, are the payment
details.

This is where we specify details
about the transaction, such as
my website's name, the total
amount, and each line time.
I kept things simple, and
decided that I'm just going to
charge $5 for everything on this
list.
Finally, the options argument
specifies what information I
need to collect from my user to
complete the transaction.

Let's switch back to the iPad
and add some supplies to my
list.

So, now that we've passed all
the information in, we actually
need to call another method to
show the sheet.
And, that's the show method on
the paymentRequest.

And, this method returns a
promise that resolves with a
payment response when the user
authorizes the transaction.
So, [inaudible] with Face ID or
Touch ID.

In here, is where you would
process the transaction.
And then, finally, you'll call
complete with a value of success
or failure, depending on the
state of the transaction.

Alright, now let's check that
out on the iPad.
There we go.

So, there are a few additional
steps you'll need to take, like
obtaining a payment session from
the Apple Pay server.
To learn more about that, please
see the sessions page on the
Apple developer website for
links to those additional
resources.
Now, finally, I realize I
haven't given a glimpse of my
readers-- what they're actually
building.
So, I want to add an image near
the top of my page of the final
product.
But, why stop at a static image?
Wouldn't it be great if you
could actually see the birdhouse
in your own environment, get a
sense of its size?
So, with the new AR Quick Look
feature in iOS 12, we can do
this with just a few lines of
code.
So, we'll go into my HTML.

And, I think this is a good
place of it.
So, all I'm doing here is adding
an image.
And, linking to a USDZ file,
that is the model of my
birdhouse, with a rel attribute
of AR.
Switch back to the iPad, and
there's our finished product.
That looks pretty nice, but now
my users can also tap on this
Quick Look, AR Quick Look icon
in the corner here.
We can see the model, move it
around, and I can also place it
in the real world, and actually
get a sense of what I'm going to
build.
So, it's actually really easy to
do this.
Please check out that session if
you have the chance.

I'd like to bring Shloka back up
on stage to wrap things up.
Thank you.

Thank you so much, Jason.
And, the AR model looks really,
really cool.
And, I think its inspired me to
try to build a birdhouse.

Not making any promises.
So, you can add custom drag and
drop features.

And custom fullscreen controls
for the iPad.
You can use the Payment Request
API to support Apple Pay, and
the Service Worker API to
support offline experiences.

Or, you can add AR models to
your content to give it depth.
And now your websites can be
viewed in Apple Watch.
I've called out several sessions
that you can reference for
individual features, but if you
have any questions right after
this talk, stop by the Safari,
WebKit, and Password AutoFill
Lab.
And, check out the link to this
session for, of course,
documentation resources and
related sessions.

Now, there are a lot, a lot of
features when it comes to Web,
and I hope that this quick
overview gives you a taste of
how Apple constantly improves
Safari and WebKit support.

So, web developers, native
developers, and extensions
developers can always offer the
best experiences possible for
their users.
Thank you for so much for
enjoying us for this-- for
joining us for this session.
Hope you enjoyed it.

And, enjoy the rest of your
afternoon at WWDC.

Looking for something specific? Enter a topic above and jump straight to the good stuff.