What's New in Core Location

Session 705 WWDC 2019

Location technologies are core to delivering context-based services within your app. Discover how the latest features in the Core Location Framework lay the groundwork for advanced ranging capabilities and delivers more options for you to clearly communicate your location needs to your users, and allow them to provide more granular access authorization to your app.

[ Music ]

Hello. [applause] Welcome to What's New in Core Location.

My name is Adam Driscoll, and I'm an engineer on the Core Location team.

I'm excited to walk you through the improvements we've made to Core Location, new in iOS 13.

So, I think this is where we all start out as developers.

We want to make our users happy, and we have an app to do it.

And then, because you're here at my talk today, I'm going to assume that the user's location is an important ingredient in how your app can make your users happy.

So, you'll want to use Core Location.

Probably you already know that your app will require the user's permission to access their location via Core Location, so zooming in a little further, you're going to need to request and react to the user's choices via our authorization prompting system and then use the rest of our API to do its thing.

Well, this is what we're here to talk about today, because in iOS 13 our authorization system and the options it presents has changed, and so has our API in the area of [inaudible].

Concretely then, we're going to talk about always authorization, which now works a little bit differently, WhenInUse Authorization which can now do more, Temporary Authorization, which is brand new, and we hope you and your user's will love it.

And then I'm going to invite my colleague, Andrea, up on stage to walk you through the applications of these things, concretely, in the context of beacon ranging.

All right.

Let's get started by looking at that prompt I just used.

You may also recognize this from the State of the Union talk.

In iOS 13, every new user authorization interaction starts with this prompt.

I do want to call out the option we're not going to talk too much about today, which is at the bottom there, don't allow.

If the user selects don't allow, then your app will not have access to their location, and it will not be able to prompt again.

So, you're probably already thinking this, but be mindful about when you present this prompt when you request for this prompt to be presented to your users.

Do it at a time when users will best understand why you need access to their location and be most favorably disposed to granting it.

Okay, but the agenda said we're here to talk about always right now, and there's no allow always authorization option on this prompt.

So, is it a mystery?

Well, if we look at how your app would request the display of this prompt, I think that mystery will begin to unravel.

So, first up, you're going to need a CL location manager, and it needs to live for a little while.

So, if you have a simple app, setting it as an instance variable on your application delegate is a good place to put it.

Then, your app would call one of these two methods, either request when in-use authorization or request always authorization.

For this walk-through, let's say it requests always authorization.

In iOS 12, this would result in a prompt that actually provided the user both options, both when in use authorization and always authorization, but now in iOS 13, it provides this one, which does not have an option for always.

However, Core Location remembers what your app asked for, so if you asked for always authorization and the user grants the most permanent positive thing they can here, which is allow while in use, then that's what you'll get.

Apple will receive when in use authorization, but it will also enter what we call provisional always authorization.

So, let's see how that will all play out.

So, on the top of this timeline here we have in blue what the user will see and in green below what your app will see.

Because under provisional authorization, these two are actually different.

So, your app asked for always authorization, and then the user granted it when in use.

Now, if the user goes to settings, they'll see that your app has when in use authorization.

But, Core Location has called your delegate back and told that it received always authorization.

So, we hope this will make it really simple and obvious what your app should do in this context.

It should use it's always powers.

It should whatever it needed always authorization to do.

We'll get more into what that might be later when we talk about when in use authorization, but for example, maybe it would set up some GEO fences and then start doing automation behavior for the user in the background based on their location.

Okay, if it does that, then Core Location will monitor for those GEO fences, and then at some point the user will enter or exit one of them, and an event will be generated.

Normally, this event would be delivered to your location manager delegate, but because your authorization is provisional, instead, Core Location holds onto it and waits for a good time to ask the user if they want to upgrade your app to always authorization.

That prompt looks like this, and finally we see a button at the bottom that does allow always authorization.

So your app has been thinking it has always authorization all this time, and the user has been thinking that is has when in use authorization.

This prompt is how we get everybody back together all on the same page in agreement.

Now, if this prompt were to appear at a time when the user does not understand why your app needs access to their location or they do not want your app to have access to their location in the background, then they can at this point respond that they'd like to keep your app in when in use authorization.

But, if you and your users are on the same page and they like what they see, they can also grant your app always authorization from here.

Either way, the provisional authorization period ends.

If your app ends up with always authorization, then it will also receive the event that started this process.

If it ends up with when in use authorization, it will not.

Okay, let's talk details.

So, first remember that while your app is provisionally always authorized, Core Location will be monitoring for and generating events that your app is interested in but not delivering them to your app unless doing so would be consistent with the when in use authorization it actually has.

Second, the prompt that the user can grant your app always authorization from will occur later.

And third, you can only start this process once.

However, you can, as in this example, request always authorization right from the beginning, or you can request when in use authorization first and then at some later point when maybe the user interacts with a feature of your app that warrants it, seek always authorization later as an upgrade.

Okay, so Core Location is monitoring and consuming events that your app is interested in.

Let's talk about when they'll be delivered to your app and when they'll be dropped.

So first, as we've seen, they'll be delivered if you app receives always authorization ultimately and not if it receives a when in use authorization.

But they also won't be delivered if the user just hasn't chosen yet.

Now, Core Location waits for a time when we think that the user is not busy in order to maximize their ability to understand what's going on and minimize the chance that they'll give a get-out-of-my-way kind of response.

So, during this time, if more events are generated on that basis, if you're monitoring requests, then those events will displace the ones that came earlier, and the earlier ones will be dropped.

And then finally Core Location will drop the event part for anything that's become just too old.

That's because it may not be relevant for your use case anymore, but it also is definitely not in the user's perspective, in the user's mind space anymore , so it doesn't help them understand what's going on.

So, finally, to be clear, I know that this process will result in dropped events at the beginning for many use cases, but we think it's really important for, but please plan on this, because you're just getting to know users in this case, and by pursuing always authorization, you're asking for a lot of trust.

All right.

I want to mention at this point that the availability and treatment of always authorization varies by platform.

So, tvOS only supports when in use authorization, and watchOS only really needs when in use authorization.

That's because access to the background runtime is very tightly constrained on watchOS, and most of our API does not provide launching behavior.

Plus, context like the watch face are effectively always in use, so if you're working on a complication, you're app probably will not need always authorization, but, probably will not need always authorization.

So, macOS similarly does not support always authorization per se, but prompting is automatic, so you'll not have to request authorization.

Which means that for iPad apps on the Mac, when in use authorization and always authorization are effectively equivalent.

Your UIKit code can and should use whichever request, whichever one makes sense from its perspective on iOS when it's running on the Mac.

All right.

So that's always authorization.

Now, we've already come up a couple of times on this question of what would your app need always authorization for anyway.

Well, let's take a look at when in use authorization and I think we'll see.

So, I think I already, I implied, but you probably already guessed that if your app asked for when in use authorization, requests when in use authorization up front and the user granted it at this prompt, then your app had received when in use authorization with no provisional period and no followup prompt.

And it would also have saved up its opportunity to ask for always later when maybe you introduce a killer new feature that really needs it.

So, how far can you go before you have to start calling that new feature killer and asking for always authorization to power it?

In iOS 12 and in early releases, this table provided the answer there.

As you can see, an app with when in use authorization can receive location updates, it can arrange beacons, it can even receive continuous location updates in the background after starting them in the foreground through the use of the blue bar or pill the background usage indicator.

But it could not start location updates directly from the background, and it could not use any of our monitoring APIs, which have the potential to launch it in the background with location-related information.

So what's a consistent feature here?

Well, you'll notice that services near the top of this chart only function when your app is in use.

While services near the bottom function, have the potential to deliver location related information even when your app is not in use.

So, in iOS 12, they're not available to apps, which only have authorization while they're in use, but what if these services at the bottom could run in a mode where they don't deliver related information to your app unless it is in use?

In this case, they'd be compatible with when in use authorization, and we can stop thinking so much about what services your app is allowed to use and start thinking more about whether, just whether it's in use or not.

So, that's what we've done in iOS 13.

Each of these green checkmarks now describes complete access to all of our API including significant location change monitoring, region monitoring, visit monitoring.

If your app is in use, it will receive that significant location change, that region entry, that visit exit, and if it's not, it will not.

So, under iOS 12, if you knew your app needed to do region monitoring, you might have stopped thinking right there about what kind of authorization you needed.

But now, in iOS 13, you should think a little deeper.

Whatever you need to do, will the user know your doing it, can the user be involved directly in doing it?

In sort, when in use authorization will be sufficient for your app's needs if it will or can be in use at the time.

Okay.

So, when is your app in use?

Well, at some point on this timeline, your app will enter the foreground, and from then, until it enters the background, it's considered in use, and then actually for a few seconds more.

So this is the grace period that's intended to cover your app for race cases when the event that you need location for happens right before the user leaves your app, but it's very short, so try not to depend on it too much.

Then your app will remain out of use until it next enters the foreground and this process repeats.

Okay.

So, if you add location updates to the list of background modes that your app supports in Xcode, then you can also get into this situation where after your app enters the foreground and becomes in use, you start updating your location, and then you set the allows background location updates property to true on your location manager.

And then when you app enters the background, that blue background usage indicator will show, and your app will continue to be in use throughout its period in the background until it enters the foreground again.

Then, at some point you set allows background location updates to false, and that's sufficient to return to the usual behavior where the next time your app leaves the foreground, it will cease to be in use.

All right.

What about complications?

Well, the complications on the current watch face are effectively always in use.

Note though that like the grace period in the background usage indicator period, this is a dark green color, and your app is not considered in use enough to request an authorization prompt in this state or to do anything but receive location updates.

So, if you're working on a complication, your app probably will not require always authorization, but you will need to seek authorization from your app context.

There's one other case I'd like to draw your attention to because it provides a lot of additional power to when in use authorization in those cases where you can afford to directly involve the user.

So, if you can do that, then you can create a local notification with a UN location notification trigger that names a region of interest.

Then, when the user enters that region, that notification will become relevant and will be displayed to them.

Note that at this point up to this point your app has not received any information about where the location, where the user is, and you're not told when this notification presents or doesn't present.

However, at this point, if the user taps through from that notification and launches your app, boom, your app is in the foreground.

It's in use in the regular way, right at the context where you needed it to be.

Okay, so remember, all the Core Location API surfaces are now available to all clients under at least some circumstances, and you can use local notifications or the blue background usage indicator to get or stay in those circumstances as appropriate, which means you should now need always authorization only for those cases, those kinds of automation where the user can't or doesn't want to be involved before your app is.

We hope that this will help you make your authorization story more comfortable for all those users in other cases.

Okay, and there's one more way in which we've made a temporary authorization, when in use authorization cooler, and that's that we allowed it to be temporary.

So, that's what the middle button on this prompt does.

Let's take a look at all the states that your authorization states that your app can be in and some of the transitions that you can make between the VR prompting system so that we can figure out where this temporary authorization fits into the picture.

So, starting with the way this works in iOS 12, when your app first enters to foreground, its state is not determined, which means that it does not have access by the way we're going to have more permanent states off to the sides and more highly authorized states up to the top.

So not determined is at the bottom.

Your app cannot access location, the user's location, but it's not denied.

It's not determined.

So, crucially, in a not determined state, your app can request an authorization prompt, and as soon as it does, then it may be denied, and then it will not be able to prompt again, but the user could also grant a when in use authorization, and if you request always authorization from there, you can get into always authorization, or you can ask directly for always authorization from the beginning.

So, that's iOS 12.

Now, in iOS 13, we've seen that the path to always authorization involves a new temporary state called provisional always authorization, which functions a lot like always authorization but from which a transition back to when in use authorization is also possible.

Well, a temporary authorization works very similarly.

It's a temporary state that behaves a lot like when in use authorization but from which a return to not determined state always happens as soon as your app is no longer in use.

Okay, so temporary, a when in use authorization is temporary, but otherwise it works just like when in use authorization.

So, your location manager's delegate will be called back with location manager did change authorization to authorize when in use and then again later with not determined.

But the key is, after that happens, your app can and should request authorization again the next time it needs it.

And the main thing to remember is just that authorization with temporary when in use authorization is closely tied to when exactly your app is in use, and also because you can request it again, it's more closely tied to where in your app's flow you actually need location access.

So, let's look at some of those green in usage charts again now in this light.

So here's the most basic case, but we'll make it even more basic by pulling that second region of usage up close to the first one.

Now, while your app is foreground and in use, let's say the user interacts in a way that makes you know that your app will need authorization, so you request authorization at that point.

And the user grants it with the allow once, the user grants a temporary when in use authorization.

In that case, your app will have when in use authorization through the remainder of that foreground period, across that brief dip into the background, and then through the next foreground period all the way until it fully enters the background at the end.

All right, but what happens if that gap in the middle opens up a little bit more and your app really ceases to be in use in between.

Then, the user does that thing, you request authorization, you receive a temporary when in use authorization, but it's going to lapse when you enter into the background.

So, you're probably thinking, okay, when do I ask for authorization again in that second period of in useness?

Should I do it as soon as I enter the foreground?

No, you shouldn't.

You should instead keep in mind what it was that caused you to ask for authorization in the first place.

For example, maybe the user asked that you keep a MAT view updated with their current location or that you GEO tag a message they're sending.

If they do that again in the second usage period, then ask for authorization to do it in order to support them with that request.

If they don't, don't.

The key is, if the user doesn't expect you to continue using their location from the previous time, don't ask again as soon as you enter the foreground.

Okay.

But, sometimes maybe you're tracking a user's run or helping them navigate, and the user will expect you to continue accessing their location even after across periods of time in the background.

Well, in that case we're probably in this situation whereas after you start that run and you ask for authorization to record it, and you receive temporary when in use authorization, you're going to be starting location updates.

You're going to be setting allows back on location updates to true.

And so when your app enters the background, that blue background usage indicator will show, and your app will remain in use and therefore continue to have its temporary when in use authorization uninterrupted across that background session.

Then, when [inaudible] in the foreground again, end the run or end the navigation session, you set allows background location updates to false again, and we return to the normal situation.

Okay, I do want to call out that there is a valid use case for requesting authorization more or less as soon as you enter the foreground, which is if the user expects your app to always have authorization, always be updating a map with their location, but only when they're directly interacting with it.

In those cases, when you enter the foreground, request authorization, but don't set allows background location updates then you won't get the background usage indicator, and your authorization will just lapse when you enter the background.

Then when you come to the foreground again, repeat.

Now, ask yourself seriously though, if the user really wants you to do this.

Maybe they do.

In such cases, you're likely to end up in more permanent when in use authorization sooner or later, but it makes sense to still ask in this way for that period of time before users are sure if they want to grant that or not.

Okay, so we've seen that when in use authorization can now handle some uses such as region monitoring and that temporary authorization can bring them that power even on a case-by-case basis, and I promised you some revamped beacon ranging API.

So I'd like to invite my colleague, Andre Guzzo, up on stage to walk you through that.

Andre.

[ Applause ]

Hi everybody.

My name is Andre Guzzo.

I'm a software engineer in the Core Location team, and I'm here today to talk to you about beacon ranging.

We'll see what's changed in the API in iOS 13 and I will walk you through a simple example on how to use beacon ranging and provide a great location experience to your users without the need of always authorization.

Let's start with a refresher about beacon ranging.

What is beacon ranging?

We introduced it in iOS 7 as an extension of the regional monitoring API and as a way to provide a new dimension of location aware experience to your users.

It's part of the region monitoring API because you want to use region monitoring in order to initiate ranging.

You want to assure you are in an area where your beacons are visible before you start ranging for them to not waste resources.

And region monitoring since its introduction has required always authorization.

Now in iOS 13, it can be used with when in use authorization instead.

So, as I said, we introduced beacon ranging as an extension of region monitoring.

So in order to represent a region which is defined by the presence of beacons, we have extended the CL region object into the CL beacon region, and among other properties, we included what actually identifies a beacon, which is [inaudible] major and minor.

And you would pass this data type to the beacon ranging API in iOS 12 and previous releases.

But let's focus on this [inaudible] it identifies exactly one beacon.

Well, you might configure the same [inaudible] on multiple beacons, but it would appear like a bigger beacon.

So, when I'm defining a region with all the elements of the [inaudible], I'm actually defining a region with exactly that beacon matching the [inaudible].

But in the beacon region case, we can omit the minor and major number, which is equivalent to using a wild card.

So, I can omit the minor number, and now my region is defined by all the beacons sharing the same UUID and major number.

In the same way, I can omit the major, and now I extended my region to include all the beacons that have just the same UUID but different major and minor numbers.

This is why in iOS 13 we introduced a data type CL Beacon Identity Constraint, in order to represent the meaning of [inaudible], which is telling me what are the beacons I'm interested into and that are defining my region.

And now, you will use this identity constraint, this data type, when you create your beacon region.

And you can later get an instance of this data type when you will need it to access the new beacon ranging API where this data type is expected.

So, let's now see how this works in practice by making a simple example.

Imagine we are building an application to be used while visiting a museum.

We want to provide the visitor with details about the object he's standing in front of without the need of having him typing in some long name or browsing through the catalogue.

To achieve this, we are going to install our beacons in the museum in the exhibition rooms.

We will use the same UUID for all the beacons that we will deploy in our museum.

We will configure a specific major number for each of the exhibition rooms and a minor number for the specific object inside the room.

Then, we need to be able to determine when the visitor is or not in one of the exhibition rooms.

We don't want to be ranging while the visitor is in the cafeteria doing something else.

We want to be ranging for beacons when we know he is one of the exhibition room and engaged with the visit.

At that point, we need to determine what is the object closest to the visitor and provide details about that one.

Finally, all this happens while our application is in use.

We can safely assume that since it's a guide for the visit to the museum, the visitor will probably be already engaged with our app, but if we want to remind the visitor about our application, we can use a local notification to trigger a notification when the visitor arrives physically to the museum, so he has a choice to tap through and start our application.

So, let's see what our app would look like.

This diagram represents the state of our application while it's being used.

We will be monitoring for our beacon defined region and react to enter and exit events, and while we are ranging, we will receive updates about the proximity of our beacons.

Let's focus on the first state, so how do we define our beacon-defined region.

As I said, we are going to install beacons in all the exhibition rooms, and we will use the same UUID for all the beacons and then major for the exhibition room and minor for the specific object.

Since we are interested in determining when the visitor enters any of our exhibition rooms, we will omit major and minor, and we will just provide the UUID when creating our beacon region.

Let's see how this looks into code.

First of all, we are going to ensure we have when in use authorization.

Then we will create our beacon constraint by providing only the UUID.

Then we create our beacon region with a new API by providing the constraint as argument, and we can start monitoring for it.

At this point, we are able to determine when the visitor is inside or outside one of our exhibition rooms.

And so we just need to react to the state change.

We have to start ranging when the visitor enters one of the exhibition rooms and stop ranging when he leaves one of the exhibition rooms.

We achieve this by defining our delegate method, and in the delegate method, we will react accordingly to the state.

If we are inside, we will start ranging.

If we outside, we will stop ranging.

And as you see we are providing the beacon identity constraint we just introduced that you can retrieve through the region.

Note that this delegate method will be called, also the first time you start monitoring, in order for you to know your initial state, so if the visitor starts your application while he's already in one of the exhibition rooms, you will have your delegate being called with the state inside.

So, you will be aware about that.

Okay, now that we know how to react to entrance and exits from the exhibition rooms, let's see what we have to do when we are inside in order to determine what the object closest to the visitor.

We want to provide information about what the visitor is actually standing in front of, and we want to know if the visitor moves inside the exhibition room what is the new object closest to him.

We only need to define our delegate method.

It will be periodically called with a status update on the proximity of your beacons, and you will receive a list of beacons already categorized by proximity.

So, it's very easy to know which one is the closest beacon and act accordingly.

So we have seen what do we need to do while our app is being used, but as I said, we might want to engage the visitor when he arrives to the museum.

Most likely, they downloaded our application the day before or a few days earlier.

So we might want to remind him to launch our application while he is inside the museum.

We are going to use user local notification for that, which is triggered by the location.

So, we will need to create an actual geographical region by providing the geographical coordinates of our museum.

Then, I actually declare that I'm interested only in arrivals.

You might want to register your notification also for departures if you want to take any action in that case.

And then we use the user notification API to register our local notification.

Okay, so this is all.

We had a brief refresher about what is beacon ranging.

We have seen what change in iOS 13 in the beacon ranging API and a simple example on how to provide a great location aware experience by using beacon ranging only when in use authorization.

And now, back to my colleague, Adam, for a final summary.

[ Applause ]

Thanks Andre.

So, what are the three things that we need to think about?

First is location authorization has changed.

It works in some new ways.

We hope that it will actually really fit your app better and help you to increase the confidence that users have in interacting with your app by letting them know that their privacy is being carefully guarded.

That means there is a call to action here to test, test your app.

Try living on it with granting only temporary authorization, temporary when in use authorization.

Does it work?

Is it irritating?

What could you do to improve this experience for your users so that they don't have to decide to grant or deny your app permanent authorization to access their location before they're ready?

And then, in the spirit of testing, ranging has a new way to help make you, help you make location-related experiences that are really great, and we have a sample in the toolkit today, which is really great for the new ranging, exploring the new ranging APIs.

Very minimal, just what you need to know.

So, if you have questions, we have two labs this week.

One is in an hour or something.

I don't know what time it is.

There's 11:00 to 1:00 today, and the other one is 1:00 to 3:00 tomorrow.

And you've already about temporary authorization in the keynote, and in the state of the union, and now this is the third time, so if you'd like to hear it a fourth time, they're going to cover it in designing for privacy today at 2:00.

There's also, in the rest of the week, a couple of mapping related talks, both indoor and outdoor that pair really well with Core Location, but they don't fit on this slide.

So, the most important thing is, enjoy your time here the rest of the week in WWDC19, and we look forward to seeing you in the labs.

[ Applause ]

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