Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2018-234
$eventId
ID of event: wwdc2018
$eventContentId
ID of session without event part: 234
$eventShortId
Shortened ID of event: wwdc18
$year
Year of session: 2018
$extension
Extension of original filename: mp4
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2018] [Session 234] What’s New ...

WWDC18 • Session 234

What’s New in Safari and WebKit

Frameworks • iOS, macOS • 45:24

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.

Speakers: Shloka Kini, Jason Sandmeyer

Unlisted on Apple Developer site

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Good afternoon, everyone. Good af-- alright. I hope you've been enjoying WWDC so far. 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.

[ Laughter ]

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.

[ Applause ]

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.

[ Applause ]

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.

Subresource integrity ensures that you don't serve compromised scripts to your users. 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?

[ Applause ]

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.

[ Applause ]

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.

[ Applause ]

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. No flashing. It's really great.

[ Applause ]

Thank you. Now, let's switch back to the Mac. 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.

[ Applause ]

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.

[ Applause ]

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.

[ Applause ]

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.

[ Applause ]

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?

[ Applause ]

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.

[ Applause ]

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.

[ Applause ]

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.

[ Applause ]

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.

[ Applause ]