Hello, everyone. Welcome to "Discover WKWebView Enhancements." My name is Brady Eidson, and I'm an engineer on the WebKit Architecture team. I'm genuinely excited to talk to you today about new features of the WKWebView API. At Apple, we love the Web. We pay great attention to detail, making sure that the WebKit framework is fast, responsive, secure and efficient so that our favorite browser, Safari, can be all of those things.
But we don't only love exploring the Web in a browser. We love seeing web technology used everywhere, and our platforms enable amazing integration of web content with native experiences.
If you primarily need an in-app web browser and don't need deep customization of that experience, SFSafariViewController is the best choice for you and your users. It handles all of the things you'd need to worry about while implementing a basic browser and beyond. Your users get Reader, content blockers, autofill and more, and you get a browser in a box. Add it to your app and give it a URL to load.
SafariViewController is easy to use, but powerful because it is built on top of WKWebView.
When you need a higher degree of configurability or are using web content in ways unrelated to browsing, you can also build on WKWebView directly.
WKWebView automatically protects your application's code and data from the complexities of the web platform by isolating web content in a separate process. This enables fast execution of web content while also providing protection against malicious actors.
SafariViewController uses WKWebView because of those benefits, and they are also why, for years, we've strongly recommended WKWebView over other alternatives. Speaking of those other alternatives, WebView and UIWebView were our original APIs for embedding web content. They've served us well, but for all the benefits WKWebView has, they tend to have the parallel drawbacks which is why they've been deprecated for a few years now and why we are striving to drive their usage down to zero. The deprecated WebViews work so differently from WKWebView, it wasn't desirable or even possible to make WKWebView APIs work exactly the same. This difference sometimes requires you to rethink how you do things. Other times, it requires us to add new capabilities to WKWebView. For those developers who have run into challenges transitioning to WKWebView, we are listening to you, and the WKWebView API is still growing. It has each year since its introduction, and it will each year going forward. On that note, I'm going to talk about new features WKWebView has in iOS 14 and macOS Big Sur.
Some will make previously difficult tasks much easier. Some will bring back things missing from the deprecated WebViews. And some are brand-new capabilities.
We have a lot on our plate to cover. First, I'm going to discuss new APIs to help you isolate your app and web content from one another...
we'll go over a few APIs to help you fine-tune the rendering of web content in your app, we'll touch on ways to get more value from web content on the native side of things, and finally, we'll touch on a topic that is more and more important each day, respecting privacy.
To help show off these new capabilities, I'm going to tell you a story that is probably familiar to many of you, and that is the story of an app. First, a little background. Like most mature software engineering organizations, the Safari and WebKit teams have many mission-critical internal tools to keep the project going.
One of these critical tools is our internal WebKittens website, to notify team members of the important updates to the department's many cats.
The website has been with us for longer than the iPhone. But of course, once iOS was a thing, somebody took it upon themselves to write the WebKittens app using UIWebView.
Also like most mature software engineering organizations, our department has a lot of duplicated effort in its mission-critical internal tools.
The Pups on Safari website is one of those to stay updated on the department's many dogs.
And like with WebKittens, Pups on Safari also has an aging iPhone app.
For such critical content, having to check multiple places throughout the day was kind of a drag, so I decided to solve that problem by writing Browser Pets, a single feed seamlessly combining both sites natively managing the interactions between them.
Since each of the original apps evolved independently, I started from scratch using WKWebView.
One of the first challenges I ran into was isolating my application's logic from the web content.
The "hello world" moment for my app was showing the WebKittens' news feed by itself. And the first thing I noticed while trying to scroll through the feed was I couldn't.
As I scrolled through the page with my finger, the page was fighting me.
That's fine for the page in the browser, but I'm doing deep customization of the experience in my app. I just want the kitties and nothing else.
So, we've deprecated that setting this year and we've added something new.
If you are not familiar with the WKWebPagePreferences API, it's pretty slick. It's a recent addition, and it allows configuring certain behaviors on a per-navigation basis.
I'm already using the newer version of the policy delegate that lets me configure web page preferences so I can present as a mobile device even when running on an iPad.
With that change, scrolling works as expected.
Now that I can scroll through the news feed at will, I want to make sure viewing the comments on a post works, so let me tap this one here.
And this is the next problem I ran into. I know from using the website and app for years that the bottom half of this page should be full of comments. Instead, it is blank.
It's time to hit up the Web Inspector.
There are a lot of fantastic improvements to the Web Inspector this year, and I encourage you to check out the session about them to learn more.
Let's take a closer look at that.
The web page expects the symbol "commentDetails" to be a function, but it isn't.
I searched for the symbol in my app and found this code.
This type of conflict is an ever-present concern when working with WKWebViews. Your application can accidentally conflict with the web content. The web content can accidentally conflict with your app.
Our own global object.
The WebKittens website is rather static, so it was a great starting point for our combined news feed.
This little utility method I've written can easily be reused with different argument values like this.
I wanted my native app to listen for new comments too so I can notify my native code, and I do that using WKScriptMessageHandler.
This API was originally designed as a one-way communications channel. To make it bidirectional to handle a reply to your script message requires some extra code.
For example, tracking each message with an identifier that can be used to look up a later reply. The more sophisticated your messaging system, the more involved your message tracking mechanism needed to be, more code you have to write and debug, and there's some race conditions you may never be able to solve.
Now it returns a promise.
Second, there's a new form of the WKScriptMessageHandler protocol that you can use which gets a completion handler attached to each message it receives.
When you call that completion handler, the promise from the postMessage is resolved.
This is relatively old web content from before when the phrase "responsive design" had even been coined. The original WebKittens app looked pretty good on early iPhones because the authors had tweaked it for that specific purpose.
This is how viewing a comment on the original iPhone looks.
This is how viewing a WebKittens comment looks on a modern iPhone, much larger than when the WebKittens app was originally written. You can see the beginnings of a native UI I'm adding to Browser Pets to allow returning from a post to the news feed.
The web content itself looks passable, but there's also lots of negative space. It looks more like a 2005-era website in a browser.
I think I can adapt the site as is to make better use of the space to make better use of the screen and to fit in better with native UI.
I decided to see if I could throw some CSS at the problem to fill my users' screens.
The CSS zoom property has been with WebKit for a dozen years, and I think it might work here applied to the entire body element.
As long as the zoom value is big enough, it caps to take up the entire viewport width which is perfect in effect. But the way I'm doing it here is a bit clunky.
Fortunately, we have a solution for that in the form of the new pageZoom property on WKWebView.
This is actually the same property that drives command-plus and command-minus full-page-zoom in Safari. And I think a lot of developers will find it useful in a lot of scenarios.
Next, let's take a look at a Pups on Safari comment. These headers and footers that you see were meant for display on the website as viewed in a browser. They're not really what I want. I have native UI to show, not these artifacts from the site.
To explore my options for removing them, I decided to learn more about them in the Web Inspector.
I noticed the elements have these classes, pup-header and pup-footer. Let's dig a little deeper and see where those are used.
So they match this custom media query for a no-header-and-footer-device.
One usually sees only a handful of media types in CSS, "Screen," "Print" and so on, and this is not one of them.
I did a little digging amongst my colleagues, and I found out that before there was a Pups app for iPhone, there was also a Mac app that used the original Mac WebView.
WebView in the Mac had this great feature where you could tell it to present itself as a particular media type. Commonly used to pretend to be a printer when you were really a screen, it could also be used for custom types. So, depending on the context within your app, the same content could have different presentation.
And we're bringing that feature forward to WKWebView on all platforms this year.
Now that I've spent some time fine-tuning how things look in my app, I wanted to explore other features I could add that focus on the web content itself.
Fortunately, there's some relevant new APIs this year for me to explore.
Looking back at that last Pups on Safari post, this was a popular post with a lot of comments.
I have a few things I can configure about the find like any find in AppKit and UIKit APIs-- the direction, case sensitivity, wrapping. Or without any configuration, it will just use sensible defaults.
If a result is found, it is selected and scrolled into view.
That joke is just not quite as funny as I remembered it. Another thing a proper app needs to do is share content.
And I can think of no content more worth sharing than the cutest web kittens and the most adorable pups on Safari.
For a few years, WKWebView has supported the ability to take a bitmap snapshot of its contents. This is useful in so many situations.
But it is limited to the on-screen content no matter how much content is actually there.
So if we add a feature to zoom in on the full-resolution version of this photo, for example, we could only capture what's visible. And this is not to mention, depending on your goal, bitmapped images might be a poor fit.
I think another great way of sharing this content would be as a PDF, and this year, WKWebView will support just that.
You can configure a few things about how you want to capture the PDF, or if you just want a PDF of all the content in the view, including content not currently visible on the screen, call createPDF with the default configuration. This code... will share this entire post, including all the comments in a searchable text form in one PDF document that would look like this.
I told you it was a popular post.
Another type of content snapshot that I often find useful when working with WebKit is the WebArchive. A web archive is an actual rich snapshot of the current DOM of the web content and the sub-resources it would need to render. In addition to being a file format supported since the first public release of the WebKit framework, it is also the native pasteboard format for web content on all of our platforms.
When I was first debugging issues with the combined news feed in Browser Pets, I wanted to leverage WebArchives to help me.
While WKWebView has been able to load WebArchive files since its first release, it hasn't been able to save them.
Until now. With createWebArchiveData, I can now take that snapshot of web content for later debugging and testing.
Like taking a bitmap snapshot or creating a PDF, it's a simple method of requesting the WebArchive data and getting the result in a completion handler.
I can save this data off to disk for later use, put it on the pasteboard, or even load it into another WKWebView right now.
As I mentioned, WKWebView has always been able to load WebArchive files. I've heard from a few developers that they thought that was not the case, so I just wanted to share the code I used to load a WebArchive, which is load(data with the appropriate mimeType.
With bitmap snapshots, PDFs and web archives, we have a growing number of ways to get stuff out of a WKWebView. And there is one more important one.
As I mentioned before, WebKittens and Pups on Safari are mission-critical tools. And some team members even rely on the ability to print out their favorite pets on actual paper for proper motivation throughout the day.
Since Browser Pets is brand new, I am of course using SwiftUI, and I've been able to build a Mac version of the app. But I know printing is important to these team members. Printing WKWebViews has been possible on iOS for a while, but Mac developers have not been so lucky, until macOS Big Sur. If this interests you, go looking for it in your SDK, and give it a whirl.
Before we get to a few more APIs that help you on the app side of things, I know many of you are also focused on the web content itself. We're always working on new Web-facing features that can shine on our platforms, and this year is no exception.
Once we're done here, I encourage you to take a look at the "What's New for Web Developers" session.
Finally, I'm happy to share with you exciting announcements regarding user privacy and how they affect developers using WKWebView.
You might have heard Apple say this before, but just in case, I'll repeat it now. We firmly believe that privacy is a fundamental human right, and that belief is legitimately one of our core values.
We've designed iOS and the App Store with this in mind. We strive to prevent any native app from using private information without user consent, not only at the policy level, but also at a technical level, and we get better at this every year. The Web is different. When users browse the wild web, they are often being watched by at least one party. There is no curator, and some web technologies seem to have evolved to encourage tracking users instead of preventing it.
We realized that with WebKit, we could do something about this.
We started working on Intelligent Tracking Prevention, or ITP.
ITP uses various client-side heuristics and machine learning to identify, classify and thwart trackers.
We've improved it continuously since we added it to Safari in 2017, and we won't stop. Since we added ITP to Safari, many WKWebView developers have been asking us to use it in their apps.
And we're happy to announce that in iOS 14 and macOS Big Sur, ITP is enabled by default on all WKWebView apps. Users have the control here. For example, if you have a general purpose web browser, your users might need to disable ITP for compatibility with a website you don't control. Most people will not fall into this situation, but there is API for you to point users towards disabling it just like we've seen with Safari.
Intelligent Tracking Prevention has proven to be a powerful way to protect user privacy in the Web, but we didn't stop there. While trying to think of other ways to protect users on the Web, we identified three common ways web content is used in an app.
The easiest to understand, perhaps, is the general purpose web browser like Safari.
The primary purpose of these apps is to show web content from any source and to help their user manage the things important to them related to the task of web browsing.
On the opposite end of the spectrum from a general web browser is an app that stays in the confines of only one or a few sites. No matter their balance of native UI and displaying web content, the web content itself is part of the core implementation of the app.
And then there's the in-app browser. Often starting from a domain specific to the app, they aggregate content from a lot of different sources, usually allowing users to start browsing from any of them. A prime example is a social media news feed, much like Browser Pets.
For these last two types of app, WKWebView has a new feature called App-bound domains. The idea is simple. You specify which domains are the core part of the implementation of your app.
This empowers you to design a secure app by implementing the principle of least privilege. Deep interaction with the web content not core to your app is disabled for both the code you write and any other code you might bring in from frameworks or libraries.
This affects me with Browser Pets. Comments on a post can have links to other domains to learn more about cats and dogs.
I want to allow these links, and I can do so safely as long as I limit my App-bound domains to WebKittens and Pups on Safari.
It would become impossible for user data to be accidentally compromised on these other domains where I don't have a deep understanding of their structure or function, or intentionally compromised if my users run across a bad actor on the Web. I don't necessarily know what nefarious plans the developers of this site might have.
Adopting it is easy. You just need to add an entry for WKAppBoundDomains to your app's info.Plist, and point it to an array of domains. Here's how I adopted it in Browser Pets. Loading any other domain still works, but deep interaction with other domains is prevented at a technological level.
It's even possible to disable deep interaction with all domains in your app by simply adding the key to your info.Plist with an empty set of values.
If you load arbitrary content but don't need any interaction with the web content itself, this is a best practice.
So, that was our journey. We took two separate apps displaying content from two separate websites and integrated them into one news feed. And the morale of the Safari and WebKit teams has never been higher.
And we respected our users' privacy out of the gate by embracing Intelligent Tracking Prevention and adopting App-bound domains. All of these features were driven directly by developer feedback. We know we haven't gotten to everyone's requests, but remember, we're not done. We can't wait for you to try out these new APIs and we genuinely want to keep hearing what else you need in WKWebView.
In addition to feedback with Apple, webkit.org has multiple ways to reach out, including a link to our Slack and to our many mailing lists. WebKit is very open source, so this is also where you can learn to check out and build as well as file bugs.
We're also on Twitter.
If you want to stay on top of new Web-facing features, Web Inspector enhancements and other goodies you might see in future releases, we usually update Safari technology preview every two weeks. Purple Safari deserves a home in your doc.
Thank you for watching, and I hope you have a great rest of WWDC 2020.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.