[ Applause ]
Hello. Welcome to WWDC.
I'm Brad Jensen and today we're going to be talking about What's New in Location Technologies.
We've got three topics that we're going to cover today.
First we're going to talk about some miscellaneous API improvements we've made.
After that we'll talk about our big change this year, how we've revised our authorization and usage reporting story, and throughout the presentation we'll also touch on best practices given the changes we've made this year.
Now, a word of warning.
This presentation is geared towards developers that are already familiar with Core Location, so if you're new to our framework, we recommend you check out our documentation afterwards.
In addition, our session from last year has a lot of helpful advice for newcomers.
So let's get started.
For users of our geocoding API, we have some exciting changes for you.
We've added support for interoperation with the Contacts framework.
So you can now forward geocode a CNPostalAddress.
And additionally, when you get a CLPlacemark result, you can get a CNPostalAddress from that placemark.
Now, this is meant to be the modern replacement for our old support for the Address Book framework.
In particular, you could geocode an address dictionary and get an address dictionary out of a placemark.
On platforms where the Contacts framework is available, we're deprecating those address dictionary API's.
However, on tvOS the Contacts framework isn't available and so you can continue to use those address dictionary API's.
We're also adding support for geocoding with a preferred locale.
This won't impact which results you get, only which language they're returned to you in.
It's important to note that the default behavior for Core Location's geocoder has always been to return results in the user's preferred language.
If you specify a preferred locale, you are overriding the user's chosen language preference.
That might sound bad, but there are actually times when it makes a lot of sense.
For example, if you're making a travel guide up, you might want to display text in your app that matches the text the user would see in the real world.
In that case you would want to provide a preferred locale to the geocoder that produces results appropriate for the region the user is visiting.
We've spent some time improving our heading updates API as well.
Before we get to that, let's just make sure we all understand the jargon.
Heading refers to the direction that you are facing, and course is the direction you're actually moving.
Now, with boats and planes you tend to see a disconnect between heading and course due to wind or sea currents.
With cars, on the other hand, you almost never see a meaningful difference between heading and course.
Even if there are very strong winds that push the car to one side or the other, the driver will tend to compensate.
They don't want to get pushed out of their lane, or even worse, off the road.
This is a very convenient observation because if we're computing GPS estimates, we're very likely to have a good estimate of the device's course, but sometimes computing the heading can be a little bit more tricky.
Even if we're able to accurately estimate the heading of the device, it might not be the right heading.
For example, let's suppose the user is navigating in their car and they've mounted their iPhone to their dashboard.
There's a very good chance that they've angled their iPhone to face themselves, but when they do that, they introduce a disconnect between the heading of their car and the heading of their iPhone, but when they're navigating, they'd really like to see the heading of their car.
Luckily, we just found a really good way to estimate the heading of the car.
We can use the course of the iPhone.
So in iOS 11 Core Location will now automatically detect situations where heading and course should probably be in agreement and it will leverage course information to provide a more accurate heading update.
It's important to note that this behavior is fully automatic and always on when you use Core Location's heading API.
So if you're creating an app for planes or boats or augmented reality, then you probably want to use Core Motion's CMDeviceMotion API instead.
Our detection logic is very good, but it's not flawless.
There are times when it will make the wrong call.
If you'd like to learn more about their API, they had a session this year.
I think it's definitely worth checking out.
We've also spent a lot of time improving our indoor positioning system.
As you saw in the keynote, Maps will now display floor plans for many indoor venues throughout the world.
At these venues any app that requests best accuracy location will automatically receive our high accuracy indoor location estimates.
We have four exciting improvements that I want to share with you today.
First, we've improved the accuracy of our estimates.
Our estimates are GPS quality or better.
Second, we've improved the responsiveness of our indoor positioning system.
When the user first enters a venue, you'll start to receive those indoor estimates much more quickly than you did in iOS 10.
We've also improved how quickly we detect floor transitions.
You'll get notified of the new floor more quickly than you did in iOS 10.
We've improved the availability.
And I don't just mean the number of venues that Core Location supports.
If the user wanders into a region of the venue that maybe hasn't been surveyed, you'll still get quality indoor estimates through Core Location.
We've improved the interoperability of the indoor positioning system with wireless accessories.
So even if the user is, say, streaming Beats 1 to their AirPods, you'll still receive quality indoor location estimates.
For watchOS we're making our continuous background location API available.
You've probably already heard about this API, but just in case, this API allows your app to receive location updates even as it enters the background.
Now, in watchOS 3 it was possible to get very similar functionality using a combination of Core Location and HealthKit.
An HKWorkoutSession would allow your app to continue receiving location updates even if your app was in the background.
However, we wanted to allow you to create new location-based experiences that weren't necessarily workout related, and so we're bringing our general purpose continuous background location API to watchOS.
Our usual guidance still applies.
This is a fairly power expensive API and so you should think twice before using it, but if you're creating, say, a navigation app or a fitness app, the continuous background location is almost certainly what you're looking for.
We wanted to ensure that this functionality was exposed in only one place, and so in watchOS 4 HKWorkoutSessions no longer give your app access to location in the background.
Legacy apps will continue to work, but when you link against the watchOS 4 SDK, you must adopt the continuous background location API.
Otherwise, your app will be unable to access the user's location.
Luckily, it's very easy to adopt our API.
There are simply three easy steps.
First, you enable the LocationUpdates background mode.
Simply navigate to the Capabilities tab in Xcode, scroll down to Background Modes, and check the Location Updates box.
Second, you need to set the allowsBackgroundLocationUpdates property to True on your Location Manager.
We recommend you only do this after the user has performed some action which requires sorry.
Getting a little ahead of myself.
We recommend you do this only after the user has initiated the workout session or the navigation session.
That way you don't accidentally start the continuous background location session before you meant to.
Finally, you simply call startUpdatingLocation while your app is in the foreground.
When your app enters the background, Core Location will keep your app running and continue to deliver location updates.
While we're talking about workout apps, we have some advice to help you create the best possible experience for your users.
First, we recommend you continue to use HealthKit, even though it's possible to create a fitness app that doesn't use HealthKit or HKWorkoutSession, doing so will make your app miss out on a lot of special tuning we've put into Core Location for workout scenarios.
So continue to use HealthKit and HKWorkoutSession.
Second, if you know that your user is in a pedestrian workout, we recommend you use CMPedometer to estimate how far the user has traveled.
In some environments it can be very tricky to accurately estimate the user's location, and if the user goes through a run in one of those environments, you'll find it's even harder to accurately estimate how far they have traveled.
But if you know they're in a pedestrian workout and you use CMPedometer, your app won't be affected by those difficulties.
Okay. That's the miscellaneous topics.
Let's get to the big one; authorization and use of reporting.
We spent a lot of time iterating on how Core Location's authorization and usage reporting works, and we've got some exciting changes that we think your users are going to love.
First, let's quickly review how it all works.
Core Location supports two authorization modes; WhenInUse and Always.
Always authorization allows your app to access the user's location anytime your app is running.
Additionally, Always authorized apps can use our background monitoring API's.
These allow your app to get runtime and receive information when various location-based events have occurred.
For example, the region monitoring API will launch your app whenever the user arrives at or departs from a region of your choosing.
The WhenInUse authorization mode allows your app to access the user's location anytime your app is considered in use.
Usually if your app is in use, that means it's in the foreground, but that's not always the case.
For example, if you're using the continuous background location API, on iOS Core Location will draw a blue bar, a blue double-height status bar at the top of the screen, reminding the user that the app is still running and still accessing their location, and in that way your app is still considered in use.
We introduced the WhenInUse authorization mode because we wanted to allow users a greater level of control over how apps access their private data.
And users love this.
They love knowing that apps can only access their location at times when they want it to.
And we think this represents a great balance between the user's ability to control how your app accesses their location and your ability to create compelling app experiences for the user.
Since we introduced the WhenInUse authorization mode the response has been tremendous.
Almost 80 percent of location-using apps on iOS support WhenInUse authorization.
A mere 21 percent have chosen to require Always authorization from the user.
Users love the WhenInUse authorization mode, and thanks to your efforts, they almost always have it available to them.
We think this is fantastic, but we wanted to see if we could do better.
Now, let's look at some of the reasons why an app might choose to require Always authorization.
We think that one of the common reasons is the developer's simply confused.
It turns out that many apps which require Always authorization don't actually use any of our background monitoring API's.
It's very likely that these apps would continue to function just fine if they were granted WhenInUse authorization instead.
But when the user encounters one of these apps, they don't know that.
They can't see the app source code.
They don't know that it won't monitor them all day and so they have to treat it as though it will, and this creates a very poor user experience.
Now, a second reason we think that many developers choose to require Always authorization is they're simply trying to give their users the best possible experience.
See, not all features can be implemented reasonably with WhenInUse authorization.
Some basically require Always authorization, and we think that these developers simply want to ensure that their users have access to all the best that their app has to offer, but this makes for a very poor user experience for the users that don't wish to grant the app Always authorization.
They are forced to choose between granting the app Always, which is more than they would like in this example, or granting it Never, which means they don't get to benefit from any of the app's location-based features.
And their final openings to grant it Always and then revoke that authorization after they're done using the app.
In any case, the user is not having a great time with this app.
So for iOS 11 we're asking all developers with Always requesting apps to additionally support the WhenInUse authorization mode.
This change is both retroactive and forward-looking, so when the user updates to iOS 11, they will be able to authorize any app that requests Always authorization the WhenInUse authorization mode instead.
If you link against the iOS 11 SDK, you must provide a WhenInUseUsageDescription.
Otherwise, your app will be unable to request Always authorization.
Furthermore, when your app requests Always authorization, we will additionally display an option to grant your app WhenInUse authorization instead.
With these new three option prompts we have a new UsageDescription string as well.
Your app needs to provide an AlwaysAndWhenInUse UsageDescription.
Since this is a different key your app must provide it when you link against the new iOS 11 SDK.
For apps linked against iOS 11 and later, Core Location will not use the old NSLocationAlways UsageDescription key.
So let's talk a little bit about best practices; how does this change things.
For apps that want Always authorization we recommend you provide all three keys, even that NSLocationAlways UsageDescription that I just said we won't use.
And the reason why is if you want to deploy your app on a device that's running iOS 10 or earlier, you need to provide strings that it can understand, and so you should continue to provide that NSLocationAlways UsageDescription.
Second, your AlwaysAndWhenInUse UsageDescription should help the user choose between Always and WhenInUse.
We'll use it in context where those are the two options presented to the user.
So your description should explain to the user what features will be enabled if they select WhenInUse authorization, and then what additional features they'll receive if they choose to grant your app Always authorization.
For all apps we recommend that you only request authorization when you really need it.
If you wait to request authorization until the user has performed some action which requires access to the location, then when the prompt appears, the user will have all the context, all this intuitive understanding that they need in order to understand why your app wants access to location.
This makes it much more likely that they'll actually grant your app authorization.
For apps that request Always authorization, there's a little bit more to that.
We recommend you request WhenInUse authorization first.
Requesting WhenInUse authorization is a little bit easier, not asking as much from the user, but there's more to it than that.
We think your app should make WhenInUse its base experience, the first thing users encounter.
Then, after the user has had a chance to explore your app and get to know all of its features, when they discover that one that requires Always, they'll try to turn it on and at that point your app can display a transition prompt that requests Always authorization on top of the WhenInUse authorization you already have.
When this prompt appears, the user will once again have that intuitive context they need in order to understand why your app is requesting Always and they'll be much more likely to grant it to you.
Let's see how that works.
So when the user first launches your app, you'll have an undetermined authorization state.
From here you can request either WhenInUse authorization or Always authorization.
Let's see what happens if you request WhenInUse authorization.
Core Location will display our WhenInUse authorization prompt, using your WhenInUseUsageDescription in the body of the alert.
Depending on the user's choice, you'll end up with either WhenInUse authorization or no authorization at all.
After this point the user can freely go to settings and adjust your app's authorization value to whatever they like.
But if the user has chosen to grant your app WhenInUse authorization, which they probably will if you're following our best practices, you can additionally request Always authorization.
When this happens, Core Location will display a transition prompt and will use that new AlwaysAndWhenInUse UsageDescription string.
From here the user can either grant your app Always authorization or keep it at its current WhenInUse value.
After your app has requested Always authorization it will be unable to request any further prompts.
So let's go back to the start.
What if you had requested Always authorization at the very beginning, right when your app launches, for example.
The user will see this prompt.
They'll see a WhenInUse option, they'll see an Always option, and they'll see a Don't Allow option.
If the user doesn't understand why your app wants access to location all the time, if they don't have that context that we're recommending you provide, then it's very likely they'll grant your app WhenInUse authorization instead, and if that happens, you won't be able to initiate a transition prompt afterwards.
Oh, and this prompt also uses that new combined UsageDescription key.
Okay. Before we move on from authorization, I'm excited to announce that on watchOS 4 Core Location will support prompting for authorization directly on the watch itself.
Previously [ Applause ]
Previously, if you tried to request authorization, watchOS would alert the user that there's a prompt waiting for them on their phone and they would have to go over to their phone and respond to it there.
We haven't got this all finished yet.
It's not in the seed you received earlier this week, but we do expect it to land in a future seed.
When it's done, all you'll have to do is rebuild your app and the next time you install it, you should start to see these standalone prompts.
Let's talk about usage reporting.
But first, let's talk about how it worked in iOS 10.
Core Location would report the location usage of your app based on which services you were using.
Most services would result in your app getting a solid arrow in the status bar and in Settings.
If you used the region monitoring service, you would instead get a hollow arrow.
And finally, if you were a WhenInUse authorized app and you requested the continuous background location service, we would draw this blue double-height status bar that I've mentioned a few times.
We felt this system was very good.
It served us well for a long time, but we thought there was room for improvement.
This system over-represents the privacy exposure of some of our API's.
Let's compare two apps; one of them using the significant location change monitoring service, and the other one using our continuous background location service.
Both of these apps will have a solid arrow continuously.
However, the app using significant location change monitoring is going to receive far less location information than the app using continuous background location.
The app using significant location change monitoring is only going to get updates when the device has actually moved a significant distance, and even then, there's a rate limit on top.
And so the app receiving continuous background location is going to get far more location information, but they have the exact same usage reporting.
Furthermore, we thought that Always authorized apps were missing out on the blue bar as a feature.
Suppose you have a navigation app that is granted Always authorization.
If the user is in a navigation session, they probably want to be able to return to that very quickly after briefly using another app, but in iOS 10 Always authorized apps don't get this blue double-height status bar.
We felt that these problems made it difficult for users to correctly interpret how apps were using their location.
For example, let's consider those two apps again; the continuous background location and the significant location change monitoring app.
Suppose the user goes for a run with the continuous background location app.
They'll go on the run, they'll come back, they'll see the solid arrow the whole time, and when they look at their map, they'll see every twist and turn they took.
When they install that app that uses significant location change monitoring, they'll see the same thing, a solid arrow.
As far as the user is aware, this app is probably receiving the same amount of information as their run tracking app.
So if users are misinterpreting our signals, we decided the best way to fix this was to adjust how we indicate location usage.
We have a new policy and we think you're going to like it.
We've changed how the arrow works.
When your app requests location information from Core Location, we display a hollow arrow.
When you actually receive location information, we'll switch that to a solid arrow for a few seconds.
We'll go through an example of how that actually works in just a few moments.
In addition, as you probably guessed, we're bringing the blue double-height status bar to Always authorized apps that use the continuous background location service.
Now, we expect that this new policy will help users understand your app's location usage more better.
So let's see.
Previously we had that hollow arrow behavior and users came to understand that the hollow arrow indicated that an app was using location in the background, but it wasn't continuously receiving updates.
It was receiving them potentially intermittently or only when specific events occurred, and so they understood that this arrow represented low-powered background monitoring.
We're now extending that understanding to all of Core Location's API's, and we think this is much better for you as the developers as well because now users will be able to see exactly how much, or as the case may be, how little information your app is actually receiving when it's running in the background.
If you're using our background monitoring API's, you'll find that you have a hollow arrow more and a solid arrow less, and we think this will help users understand that your app is not actually receiving every single step, every twist and turn throughout their day.
Okay. So let's look at how that arrow works in practice.
Here we have a test iPhone and it's currently at AT&T Park and let's suppose an app is using the Visit monitoring service.
The device has been stationary here for a long time and so we're displaying a hollow arrow in the status bar because Core Location is not delivering new information to the app.
However, once the user gets up and starts moving towards, let's say the Ferry Building, Core Location will detect that departure event and alert the app.
That will result in a solid arrow appearing in the status bar for a few seconds.
As the user continues their journey the arrow will return to its hollow state and it will remain hollow until Core Location detects an arrival event.
After it detects that, it will launch the app once again and the app will receive a solid arrow that will linger for a couple of seconds, and then after that it will remain hollow until the user departs from that location.
We really hope that this new policy helps users better understand exactly when and how your apps are accessing their location, and we think that it will result in users no longer blaming your app for things it's not actually doing.
That's what we've got for today.
And just to recap, there are three important points I want you to remember.
First, users have more control over how your app accesses their location.
Specifically, users can now grant your app WhenInUse authorization if you request Always authorization.
Now, we always recommend that you communicate with the user and help them understand why your app wants access to location, but apps that request Always authorization have an even greater responsibility.
If the user doesn't understand why your app wants access to Always authorization, then they're not likely to grant it to you.
They're likely to give you WhenInUse authorization instead.
So you have that greater responsibility if you want to receive Always authorization.
And the best way we think that you can communicate with the user to help them understand why you're asking for Always authorization, the best way to maximize your chances of receiving Always authorization from the user is to give them that context that I talked about earlier.
Give them that intuitive understanding.
Let them explore your app with WhenInUse authorization, and then when they try to enable that feature that requires Always authorization, then you initiate that transition prompt and they will almost certainly grant your app authorization at that time.
Thank you for your time.
If you'd like to learn more, we have some supplementary material online.
We've updated our PotLoc app, for example, so you'll find that's got some new goodies for you.
We also recommend you check out these related sessions.
I've already mentioned the Core Motion one, but the Privacy session from earlier this week was also very good and it has a lot of great advice to help you build an app that respects the user's privacy.
Thank you for your time, and I hope you enjoy the rest of WWDC.
[ Applause ]