Introducing Safari View Controller

Session 504 WWDC 2015

The new SFSafariViewController class enables you to deliver interactive web content in your app just like Safari, including the key Safari UI elements already familiar to your users. See how to easily bring Safari features like Reader and AutoFill into your app, and provide a great web viewing experience with fewer lines of code.

RICKY MONDELLO: Good afternoon everyone.

Welcome. Before we get started I just want to get a little feel for the crowd.

Little show of hands.

Please raise your hand if you have an app that's currently being distributed on one of the App Stores.

That's a lot of you.

Welcome, you're at the right place, it's WWDC.

And how many of you are just learning how to write iOS, Mac, or Watch apps now and just getting started?

A few of you.

Welcome to you as well.

And of all of those apps that you've built or you're thinking about building, how many of them are a dedicated web browser?

Okay. A few of you.

Not that many.

But how many of you have a miniature web browser that's within your application that you show whenever a user taps on oh my God, all the hands are up.

Yes, my name is Ricky Mondello, I'm an engineer on the Safari and WebKit team, and my goal for the next half hour is to get all of you out of the business of writing those miniature web browsers.

(Cheers and applause.) RICKY MONDELLO: I'm going to show you how you can use either Safari or the new Safari View Controller to give you more time to focus on the parts of your app that are special to your app.

And to give your users features that they already love from Safari.

So if you're ready, let's get started.

At the center of this topic is web content.

And web content comes in all sorts of different shapes and sizes, but for today's discussion I'm going to lump it into two different buckets.

The first bucket is content within your app that just happens to be written in HTML, JavaScript, and CSS.

It's content that you own or content that you're giving a special presentation to.

The important part, is that it's not content that looks like a traditional web browser.

It's not when a user is browsing on a website.

Which brings us to the second case.

When a user taps a link in your app and you want to show them a view that's kind of like Safari, so they can do some short-term browsing.

This session is primarily focused on the second use case.

We're going to see how both Safari and Safari View Controller can add years of features and polish to your applications.

But before we do that I want to touch on that other use case real quick.

If you're using web content within your app but in a way that doesn't look like a traditional web browser you might be using WKWebView or UIWebView, but WKWebView is the preferred tool to do this; it's your friend.

It was introduced in iOS 8 and OS X Yosemite, and basically it's just a rectangle around web content.

You load a page into it, you can evaluate JavaScript and get a result from that JavaScript against the current page.

You can modify navigations or outright block them.

And it's up to you to add your own user interface.

Back, forward buttons, communicate progress, et cetera.

And new on iOS 9 and OS X El Capitan we've heard your feedback and we've incorporated some of the pieces of WKWebView that were missing.

First and foremost, you can securely loadFileURLs now.

(Applause.) RICKY MONDELLO: You can also loadData, say literal HTML string that you wanted this way.

No need to spin up a server.

And if you like, you can set your own customUserAgent string.

(Applause.) We've also added a new API to manage the data that is stored by websites like cookies and caches and other stuff.

And it's called WKWebsiteDataStore.

It's a read/write property on your web view's WKWebViewConfiguration.

And with the data store you can remove data by its type or you can do something like remove all data that was added in the last hour, which is pretty cool.

And because the property, the store on your configuration is writable you can replace it with a configuration that's non-persistent which is exactly how you'd go about implementing private browsing.

So for web content that's in your app that you own, you control, or you're customizing, WKWebView is the right tool for the job.

And in iOS 9 and OS X El Capitan we've given you more flexibility than ever before.

But if you've have been sitting here thinking: I don't need that flexibility, I don't want to evaluate JavaScript against the page.

I don't need to modify navigations.

I don't want to wire up my own back and forward buttons, then the rest of this talk is for you.

We're going to talk about how you can use either Safari or Safari View Controller to get a better experience for your users and to give you less code to write.

And your first option is to simply delegate the responsibility of showing web content to Safari itself.

And this is super easy to do.

You just call UIApplications, openURL method and iOS will switch away from your app and over to Safari.

And new to iOS 9, the system affordance that you saw yesterday for going back to the last app, makes this a better option than ever.

It's more lightweight than iOS 8 was.

(Applause.) RICKY MONDELLO: And delegating the responsibility of showing web content to Safari ensures that users get a first class experience with that web content.

That's what Safari is all about.

But if you'd like to maintain your app's current experience, where users never even leave your app, then you're going to be interested in Safari View Controller.

Let's take a look.

This is Safari View Controller with the page from apple.com with the web contents slightly grayed out.

The first thing you'll probably notice is that Safari View Controller looks a lot like Safari with a few intentional differences.

Safari View Controller's job is to make it fast, easy and enjoyable for users to tap on a link within your app, view a web page and press done to go right back to your app.

Safari View Controller eliminates distractions.

The URL field that you see up there, it's read only.

You can't change it.

And there's just this one page.

No other tabs to distract the user.

And with Safari in the name, Safari View Controller brings features that your users already love from Safari, but now they're in your app.

Let's start off, first and foremost Safari View Controller shares cookies with Safari and other website data.

So what this means is if one of your users is already logged into a website in Safari, if they tap a link in your app and Safari View Controller comes up they might still be logged in.

But if they're not logged in already, we've got that covered too, because Safari View Controller allows you to use Password Autofill to fill any of the passwords synced across all of the user's devices with iCloud Keychain.

But before we go further it's really important to point out this is completely safe for your users.

And the reason that this is safe is because we're giving your users access to their credentials, their user names and passwords, but we're not giving access to the host app to this data.

In fact, Safari View Controller runs in a separate process from your application.

Which categorically frees you from the responsibility of thinking about this important sensitive user data.

That's on us.

All right, let's go back to features.

When a user wants to have something shipped to their home or to their work they'll be able to use Contact Card Autofill to fill that information just like they could in Safari.

And when it comes time to make a purchase they'll be able to fill their credit cards as well.

And if one of your users comes across an article that's interesting, compelling, but difficult to read, she will be able to use the Safari Reader button in order to show a simplified cleaned up version of that content.

Super great.

And new to iOS 9 in both Safari and, of course, in Safari View Controller, Reader is customizable, offering a bunch of themes and some fonts to choose from.

So it's never been easier to read articles on the web exactly the way you want to and your users want to.

From the share button you'll find exactly what you expect.

You'll find the system wide options for sharing to social networks and you'll also find the ability to add to one's reading list, but that's not all that you'll find here.

Because alongside these activities are activities that your app provides to Safari View Controller.

So if your app is a social network, you can have a dedicated button in the share sheet to share the current web page to the social network.

Really cool.

And while we're on the topic of customization, Safari View Controller will respect a custom tint color that your app sets on it.

So in this case up on the slide the tint color has been changed from Safari's default blue to orange.

This is a great way to let users know which app they're in when using Safari View Controller.

This next feature is really awesome and it's new to iOS 9.

It's called Content Blocking go ahead!

(Chuckles.) (Applause.) RICKY MONDELLO: So the big idea behind Content Blocking, is that it's possible to add something to the experience of viewing a web page by taking something away.

In iOS 9, any app can write a description of web content that Safari and Safari View Controller should block as the user browses the Web.

So lets take a look at an example.

Here's a web page that has some pretty cool content, but in my case I really don't like all of the clickbait headlines that are in that side bar.

So if you install the right content blocker you won't believe what happens next.

(Chuckles.) Oh, well, you will.

The content disappears.

(Applause.) RICKY MONDELLO: But that's not all that Content Blocking is capable of.

Content Blocking can do a lot more than hiding elements on a page.

You can out right block loads from happening.

You can block all images or all scripts from a third-party domain that you're not really fond of.

And all of the content blockers that a user turns on in settings will apply in both Safari and in Safari View Controller.

So what this means for you is after you've switched your miniature web browser implementation over to using Safari View Controller you won't get any complaints that your users' ad blocker is not working.

Pretty cool.

So that's a bunch of features.

Let's talk about safety.

I mentioned a moment ago that Safari View Controller runs in a separate process from your app which frees you from a lot of responsibilities of thinking about important user data.

But when it comes to browsing web content, it's just as important to have an expressive interface that communicates security to a user, and Safari View Controller does the same exact job that Safari does in this regard.

First and foremost secure pages.

Safari View Controller communicates the validity of SSL to your users just like Safari does.

But if the user is having a bad day and they come across a phishing page, Safari View Controller will also warn them about that and ask them to turn around, exactly the same way that Safari would.

So to recap, Safari View Controller has all the great features of Safari itself.

The features that your users already love.

Like the ability to fill their passwords, have shared cookies, clean up articles with Safari Reader and in iOS 9, Content Blocking.

There are also a few other minor things like correctly communicating progress while progress is loading with a nice progress bar.

And showing informative error pages when something goes wrong during a load.

Your miniature web browsers may or may not be doing all of these things, but with Safari View Controller it doesn't have to, because adopting it will add years of Safari features and polish to your apps and future years of polish in the future.

I'm happy to say that adopting Safari View Controller is really easy.

Let's take a quick walk through the API.

In code, Safari View Controller is known as SFSafariViewController.

It's part of the Safari Services Framework.

And as you might have guessed it's a subclass of UIViewController.

It has a delegate which I'll get to in a moment, and initializer which takes a URL.

This is the URL of the web page that your user tapped on, the web page that you want to show.

Let's look at that delegate real quick.

The first method in the delegate is how you can provide your own custom activities to the share sheet when the user taps on the share button.

And the second delegate method is called when the user taps on the done button, when they're done browsing.

You're going to want to implement this in order to dismiss the View Controller.

Taken all together it's a pretty simple API.

And to show you just how powerful this simple API can be and how many lines of code it will remove from your apps, I'm delighted to invite my colleague Yongjun to the stage for a demo.

Yongjun.

YONGJUN ZHANG: Thank you, Ricky.

Hi, everyone.

My name is Yongjun.

I'm a Safari and WebKit engineer.

I don't know about you, but I really want to have some pizza today.

So I'm writing an app to find pizza stores around me.

Here it is.

I call it pizza finder.

I got a list of pizza stores.

If I select the first store, I got the phone number, address, I also get a link to the website of the store.

My task now is to make my app show the website so I can know more about a store.

As Rick mentioned we got three options.

Option one, use openURL and let Safari open the website for us.

Option two, you establish a web view and make our own browsing app.

And option three, use Safari View Controller.

I am going to try option one first.

So I go to my Xcode project.

And here in my store view controller I got a function here, showStoreWebsite.

I just need to drag one line of code UIApplication, openURL.

This will let Safari open the URL.

Lets test it.

I run the app and select the first store, left click.

Now, Safari opens the website for me and I can see this page has a Reader.

And if I try to order pizza, I got my user name and password autofilled.

So I must have been to this site before and maybe I ordered a pizza before.

Now I'm in Safari.

What I really want is my users to always stay in my app.

I don't want them to switch to Safari just for visiting one or two websites.

Because they can get distracted and might not come back to my app later.

So I really need a browser in my app.

I'm going to try option 2 now to make my own browser.

So first thing I want to do, I want to go back to my app.

So as we know, if we have some web content in the app and if the web content happens to be my UI or part of my UI, WKWebView is the best tool for that job.

In my case I wanted to use WKWebView to load web pages certainly, but I also want to have some UI around that.

For example, I want to have a URL bar on the top to show the URL.

I also would like to have a toolbar in the bottom to do back and forth navigation.

WKWebView is a very rich API, it provides a number of delegates I can use to listen to page load events or navigation events.

I can use this delegate to drive my UI.

So to save us some time for this demo, I already have a single browser.

Let's take a look.

So in the Xcode project I switched to another tab.

I wrapped my simple browser into one view controller.

And in the middle I got WKWebView.

On the top I got the navigation bar.

I use the navigation bar's title to show the URL.

In the bottom I have a back and forth button to do back and forward navigation.

Now this is a simple class.

It has about eighty lines of code.

It took me about one hour.

I believe we can do better.

But anyway, let's test this browser.

So I go back to my store view controller, remove this line we just added and drag a couple lines here.

What I am doing now is I load my view controller from the story board assigned a URL to it and presented it.

Now let's take a look.

I run my app.

Select the first store and tap the link.

This is my browser.

It runs in my app.

I don't have to switch to Safari to visit this site anymore.

That's good.

The URL bar is actually grayed out.

So it won't be distracting.

But also notice when I drag the page I don't have the dynamics of Safari's UI.

And this page doesn't have a Reader.

It will be harder for me to read now.

And if I try to order pizza, I don't have my user name and password autofilled.

So it will be harder for me to order pizza now especially when I'm hungry, and impatient, and I don't have my password.

(Laughter.) YONGJUN ZHANG: So, what I really need is some simple and easy way to show a website from my app.

I don't want to spend my time to implement missing features like progress bar.

Even though I want to spend time there are some features I will never get to.

For example, Password Autofill.

I would never get users' passwords for this website.

Luckily in iOS 9 we have a Safari View Controller.

Let's take a look.

So to take Safari View Controller into use, first thing I need to do is import Safari Services Framework and then I need to make my view controller conform to SFSafariViewControllerDelegate protocol.

In the code, let's go back to showStoreWebsite.

I don't need my browser anymore, so I remove that.

And just drag a couple of lines here.

What I'm doing now is I instantiate my SafariViewControler object, gives delegate and present it.

Before we test it I also need to implement safariViewControllerDidFinish, when the user taps the done button, and we can dismiss the view controller.

Since we are here we don't need our browser anymore, so we can delete the whole thing, move to Trash, yes.

Eighty lines of code down and one hour saved.

Let's run again.

Select the first store.

Look! I have Safari in my app.

So I got Reader back.

The same dynamics as Safari, and if I try to order pizza now I have my user name and password back.

As you see, with a couple lines of code I have Safari in my app.

You can do that for your app, too.

And the user would be really happy about it.

Thank you.

(Applause.) YONGJUN ZHANG: Back to you, Ricky.

RICKY MONDELLO: Thank you, Yongjun.

That is awesome.

So Yongjun just showed you that although it's easy to write your in-app web browser in WKWebView, it's kinda hard to get all of the details right.

He also showed you by changing about seven lines of code he was able to replace the whole thing with Safari View Controller.

You got to see how Safari View Controller has features like Password Autofill and Reader and little touches like the dynamics when you scroll down on a web page.

When we started a few moments ago I divided the world of web content into two buckets.

The kind of stuff that is custom within your app that you're going to use WKWebView for, or actual websites when a user taps on a link in your app which you'll use Safari or Safari View Controller for.

But for a number of you in the audience there's actually a third use case for web content that I would like to talk about real quick.

That's doing Web-based authentication using web content.

So you've all probably seen this before.

You're in an app and the app wants to use some third-party website's accounts.

The app pulls up a web view.

You type in your user name and password.

Log in. Then you accept or deny the app's request for the resource from the third-party service.

You've all probably done this before.

But one flow that does this is OAuth.

I would like to walk through at a high level exactly how that works.

So in this flow there are three different actors.

The first actor is an app.

Let's say that it's your app.

The second actor is a user.

Let's say it's one of your users.

And of course, there is the third-party web service that your app would like to authenticate against.

So what will happen is in this flow while the user is using the app, presumably they'll tap on a button somewhere that says log in.

The app is going to package the user up with a token representing what it wants to request from the website.

And then, the app is going to present, somehow, a web page to log in against.

And the user will enter their credentials, log in and accept or deny the request.

And then be sent back over to the app.

At that point the website is going to remember that token and know whether it was approved or denied for use.

And when the app wants to connect to that third-party service in the future it will do it using that token.

The major goal of a scheme like this is to protect a user's credentials so that an app doesn't have to remember them.

Instead the app gets a token.

That token can be used at a later date to request resources or the user could revoke the token without having to change their password.

This is great for users.

If you are implementing this today, you are probably using UIWebView or WKWebView to do it.

But I'm happy to tell you that Safari View Controller is great for this purpose.

It's awesome for web-based authentication.

One of the reasons it is awesome for web-based authentication is the security story.

It's just as secure as Safari itself.

Because it runs out of process, and Apple will never get to see a user's user name and password while they're logging in.

And when it comes to protecting a user's data, one of the best ways to do that is never to have access to it in the first place.

That's our approach whenever possible at Apple.

But it is also an awesome user story.

Because since Safari View Controller has access to a user's credentials, synced across all of their devices with iCloud Keychain, logging in is going to be a breeze.

They may not need to use Autofill.

They might already be logged into that third-party web service.

Simply put, users will be much more likely to authenticate against that third-party web service, if you are using Safari View Controller compared to something that you rolled yourself.

And I'm happy to say this is also super easy to adopt.

It takes two steps.

The first is where you would've used your own in-app browser, just present an instance of SFSafariViewController.

And once the user is finished logging in and the third-party web service redirects back to your app with the custom URL scheme that you fed it, you can accept that in your AppDelegate's handleOpenURL method.

From there you can inspect the response and dismiss the instance of SFSafariViewController because you know that the authentication is done.

That's it.

Two steps.

And you've replaced your in-app browser with one that has all of the user's user names and passwords available for Autofill.

Users are going to be delighted by this and you are going to have more users log into that third-party web service.

Okay, let's cover everything we talked about today.

Web content is everywhere and it comes in all sorts of shapes and sizes.

But if you are using it within your app in a custom way where you own the experience or you're customizing it, WKWebView is the right tool for the job.

You might still be using the older UIWebView, but WKWebView is modern and includes the modern JavaScript engine that Safari itself uses, it's much faster.

And now in iOS 9 and OS X El Capitan, it has much more flexibility for you.

If you'd like to learn more about adopting WKWebView, you can see last year's session, Introducing the Modern WebKit API.

But if your task with web content is different, if your task is to show a website when a user taps on a link, your use case and needs are completely different.

In the past, you may have built your own in-app web browser with UIWebView or WKWebView, but that's always had downsides, it didn't have any of the features or state that Safari has.

And more likely than not through no fault of your own your app's implementation was different than that of other apps that the user has installed, which leads to a confusing experience sometimes.

Your first option forgetting out of the scenario is delegating the responsibility of showing web content to Safari itself.

And the system wide ability to go back to the last app makes this much better than it has ever been before.

But if you would like to maintain your current user experience where users never leave your app, Safari View Controller will add years of features and polish and features and polish in the future.

For you, it'll mean having more time to work on the parts of your app that are special about your app, the parts that you want to work on.

For your users, it will mean having new features like Safari Autofill, Safari Reader and Content Blocking.

And while I still have your attention I have a quick favor to ask of you.

Please keep filing bugs and feature requests, when there is a gap between what is and what you think should be on the platforms that you are developing on.

One of the reasons that Safari View Controller exists is because so many of you told us that you wanted it.

And now that it does exist as you're trying it out over the next few months, please let us know how we can make it more useful to you.

We really do appreciate your feedback.

Okay. You can get more information about anything we covered today at the usual places.

Or you can hit up John Davis, the Safari and WebKit Evangelist.

And we have some related sessions that you might be interested in.

To call out two in particular, in Seamless Linking to Your App you'll learn about Apple's solution to the problem of inner app linking which involves taking your website's URLs and making them universal, allowing them to open your app on your users' iOS devices.

It's really cool.

In Safari Extensibility, you'll learn to write one of those content blockers that I mentioned earlier, that will apply to all pages that are loaded in either Safari or in Safari View Controller.

If you want help with anything I covered today, the Safari and WebKit Labs are the right place to go.

And the first one is happening in about a half an hour in Media Lab A.

Alright, thank you so much everybody.

I hope you have a fantastic WWDC.

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US