Transcript
[ Music ]
[ Applause ]
>> Good afternoon.
I'm Brad, and today
we are going to talk
about Core Location
best practices.
Now just so we're
all on the same page,
we're going to start
off by talking
about the major features
of Core Location.
For veterans of our API,
this will be largely review.
But for newcomers, it will be--
well, you'll want to
consult the documentation
after this session.
After that, we'll switch over
to talking about best practices
for using Core Location.
Now iOS is the only
platform where all
of our APIs are available, so
it will be our focus today.
of our APIs are available, so
it will be our focus today.
However, if you are interested
in macOS, tvOS or watchOS,
you might want to stick
around, because a lot
of the content will be
applicable to those platforms,
and we'll talk about them
explicitly at the end.
With that, let's
get started talking
about Core Locations,
major features.
The first one is the
authorization API.
Now, you should know that the
authorization API is required
in order to access
the user's location.
You've probably experienced
this as a user,
if you've ever seen a
prompt like this one.
Here, Core Location is
asking the user if they'd
like to authorize the camera
app to access their location.
We offer two different
versions of authorization
that your app can request.
The first one is
when-in-use authorization,
and just like it sounds like,
when your app receives
when-in-use authorization,
it is allowed to access the
user's location whenever it is
in use.
We'll define what it means to
be in use in just a moment.
If you'd like to request
when in use authorization,
If you'd like to request
when in use authorization,
you simply call the
requestWhenInUseAuthorization
method.
We also have
AlwaysAuthorization.
When your app has
AlwaysAuthorization,
it is permitted to access the
user's location whenever your
app is running.
To request it, you simply use
the requestAlwaysAuthorization
method.
Whichever authorization
level you choose to request,
you must provide a
usage description
in your app's information
property list.
Core Location will pull this
string out of your info plist,
and display it to
the user as part
of the authorization prompt.
So when is your app
considered in use?
Well, if your app is
in the foreground,
then we'll consider it in use.
This is Potluck, our sample app.
If your app is in the
background, but has a blue bar,
then it will also be
considered in use.
If you're wondering about the
blue bar, we'll talk about that
in just a few moments.
Finally, if your app is handling
WatchConnectivity messages,
from a foreground watchOS app,
then it will also be
considered in use.
Once your app has received
authorization from the user,
it can use our location
sensitive APIs.
The first one we are going
to talk about is the bread
and butter of Core Location,
the standard location service.
It comes in two different
versions.
The first version is
the single location API.
When you call Request Location,
Core Location will do its best
to produce an estimate
of the user's position,
and then deliver that
to your delegate.
We also offer the
continuous location API.
When you call Start
Updating Location,
Core Location will produce a
stream of location updates,
and deliver them all
to your delegate.
Remember to stop your location
updates when you're done,
Remember to stop your location
updates when you're done,
since otherwise Core
Location will continue
to compute locations.
We have a few knobs
and dials you can turn
to adjust how the standard
location service works.
For example, Deferred Updates.
When you enable deferred
location updates,
you're telling Core Location
that it's acceptable for us
to deliver location updates
to your app in large batches.
Sometimes we do this
for power reasons.
We also offer automatic pausing.
This is enabled by default.
What it does, is it
attempts to detect
when your location session
has outlived its usefulness
to some extent.
Let's consider an example.
Suppose the user is
using a run tracking app,
and they go for a run, but when
they get home, they're tired,
and they just want to take a
shower, and they forget all
about stopping their
location session.
Now, unless the app
was specifically trying
to detect this sort
of situation,
it's likely that the
user's phone would continue
it's likely that the
user's phone would continue
to compute locations until
it runs out of power.
With automatic pausing,
Core Location will attempt
to detect situations like this,
and automatically stop
the location updates.
Core Location also
has special support
for using the standard location
service while in the background.
Once you engage one of
these special sessions,
Core Location will keep your
app running and continue
to deliver location
updates to it.
If your app has when-in-use
authorization,
we'll automatically display
a blue bar at the top
of the screen, thus marking your
app as in use, and allowing it
to continue to receive
location updates.
An always authorized app will
still get this background
running behavior, but
it won't get a blue bar.
It's important to remember
to stop your location session
when you're done,
otherwise it will continue
potentially indefinitely.
In order to start one of
these background sessions,
there are three things
your app must do.
The first one is you must
enable background location
in your information
property list.
Now, the easiest way to
do that is to navigate
to the capabilities
tab in Xcode,
scroll down to the
background mode section,
and check the location
updates box.
Second, you must set your
allowed background location
updates property to true.
This indicates that that
particular location manager
would like to be able to start
a background location session.
Finally, you must start
your location updates while
in the foreground.
If you don't start your
updates in the foreground,
you won't get this
special behavior.
So what happens if you do start
your updates in the background?
Well, first off, your
app will probably need
AlwaysAuthorization since
your app won't be considered
in use at that time.
Furthermore, Core Location
won't take any action
to ensure your app
continues to run.
So if you have background
runtime for some reason,
and you decide to start
a location session,
you might get some updates,
but you might also get suspended
before you receive all the
information you had
hoped to receive.
After the standard
location service,
we have our background
monitoring APIs.
The first one we are going to
talk about is region monitoring.
Region monitoring allows your
app to specify a location
that is interesting to it,
and Core Location will attempt
to determine whenever
the user has arrived at
or departed from that location.
This will continue even
if your app is suspended
or in the background, and Core
Location will launch your app
into the background if necessary
to deliver information
about the event.
We have two different versions
of the region monitoring API.
First, we have circular
region monitoring.
When you start circular
region monitoring,
you describe a circular
geographic region
that is interesting to your app,
and Core Location will attempt
that is interesting to your app,
and Core Location will attempt
to detect entries or exits
from that circular region.
We also have Beacon
region monitoring.
Beacon region monitoring
attempts to detect proximity
to iBeacon devices that match
a specification provided
by your app.
In either case,
region monitoring consumes
a limited system resource,
and so Core Location
only allows your app
to install a limited
number of regions.
However, keep in mind,
if you're writing an app
that uses Beacon
region monitoring,
a single beacon region
can monitor
from many iBeacon devices.
When you're ready to
start region monitoring,
you simply construct
a CL region,
either a CL beacon region
or a CL circular region,
and then pass it to the
startMonitoring(for:) method
on CL location manager.
When you're done, pass the same
region to stopMonitoring(for:).
If you want to use
region monitoring
If you want to use
region monitoring
to trigger a notification, you
might be interested to know
that the user notification
framework has special support
for this through their
UNLocationNotificationTrigger
class.
The user notification
framework is new in iOS 10,
but this functionality
was previously available
through UI local notification.
If you'd like to learn more
about the new user notification
framework, you might want
to view the Introduction to
Notifications session online.
Similarly, the HomeKit
framework has special support
for triggering a
HomeKit scene in response
to a region monitoring event.
The HM LocationEvent
allows you to do this.
If you'd like to learn more
about using HM location event,
I would encourage you to view
HomeKit session from last year.
You can find it online.
In either case, you only need
when-in-use authorization
to use the user notification
framework,
or the HomeKit framework special
support for region monitoring.
General purpose region
monitoring
through Core Location
requires AlwaysAuthorization.
Similar to Beacon
region monitoring,
we have Beacon ranging.
Now, every iBeacon device
broadcasts three components
of information: A UUID, a
major ID, and a minor ID.
When a beacon region
event fires,
you usually don't receive all
three components of information.
Using Beacon ranging, you can
fill in the missing details.
Ranging is also useful for
determining an estimated range
from the user's device
to the iBeacon device.
Now, range estimates are most
accurate when your app is
in the foreground, but
you can use Beacon ranging
in the background.
If you do, however, keep in mind
that Core Location won't prevent
your app from being suspended,
and so you might be suspended
before you receive all the
information you had
hoped to receive.
information you had
hoped to receive.
As an aside, if you're
interested
in using iBeacon devices, I
would highly encourage you
to visit
developer.apple.com/ibeacon.
Once you agree to the iBeacon
license, you'll be able
to download the official
iBeacon specification
for what every well-behaved
iBeacon device must do.
The next background monitoring
API we are going to talk
about is the significant
location change monitoring API.
As the name would imply, this
monitor's for large changes
in the user's location on the
order of about a kilometer.
Since we introduced this,
quite a bit has changed
in Core Location,
and at this point,
we believe that it's
fairly unique.
A lot of apps that use
significant location change
monitoring would be better
served by visit monitoring.
On the topic of visit
monitoring,
visit monitoring deploys
sophisticated algorithms
to monitor for places that the
user might consider a noteworthy
part of their day.
That's why we think many
apps would be better served
by visit monitoring.
After all, you're
usually interested
in where the user
stops and spends time,
rather than where
they happen to be
when Core Location has
detected a large change.
We've gone to great
lengths to ensure
that visit monitoring has
a fairly low power cost,
and so you should feel
comfortable using it
in an all-day scenario.
Like the rest of our
background monitoring APIs,
visit monitoring will continue
even when your app is suspended,
and will launch your
app in the background
to deliver event information.
If you'd like to start
visit monitoring,
you simply call the
startMonitoringVisits method.
When you're done, call
stopMonitoringVisits.
The final API we
are going to talk
about today is the
geocoding API.
Core Location supports
both forward geocoding,
that is converting an
address into a coordinate,
and reverse geocoding, which
is converting coordinates
and reverse geocoding, which
is converting coordinates
into an address.
Unlike the rest of the APIs
we have talked about today,
geocoding does not require
user authorization, however,
if your app is authorized to
access the user's location,
will automatically
use that information
when performing forward
geocoding.
That is, converting an
address into coordinates.
The geocoding API
is rate limited,
and so you should try not to
send too many requests to it.
A great way to avoid hitting the
rate limit is the cache results
provided by the geocoder.
That way, you don't have to try
to geocode the same
information multiple times.
We also recommend
that you only geocode
in response to a user action.
For example, if the user
drops a pin on a map,
that's an excellent time
to geocode that location.
Okay, now that you're
familiar with all of our APIs,
let's take a look at
authorization again.
let's take a look at
authorization again.
If your app has when-in-use
authorization
or always authorization,
it can use the standard
location service,
those special background
location sessions, remember,
that is starting
in the foreground
and then entering the
background, and Beacon ranging.
If your app has always
authorization,
it can additionally use our
background monitoring APIs.
That is region monitoring,
visit monitoring,
and significant location
change monitoring.
Don't forget that the user
notification framework
and the HomeKit framework
allow you
to do special purpose
region monitoring
with when-in-use authorization.
As far as availability
is concerned,
all of our APIs are
available on iOS.
On macOS, you can use the
standard location service,
circular region monitoring,
significant location change
monitoring and geocoding.
On watchOS, we support the
standard location service,
and geocoding, and
finally, on tvOS,
and geocoding, and
finally, on tvOS,
you can use the single location
API, and the geocoding API.
Alright, let's get started
talking about the best practices
for using Core Location.
The user's privacy is
the most important part
about using Core Location.
Location information
is highly sensitive.
It describes where we
live, where we work,
and who we spend our time with.
As such, you must
respect the user's privacy
when using Core Location.
And that is worth repeating.
You must respect
the user's privacy
when using Core Location.
Core Location helps facilitate
this using our authorization
system, but getting
the user's permission
to access your location,
sorry, their location,
is only the first step in
respecting their privacy.
You should make sure that your
app doesn't request any more
information than what it
absolutely needs in order
to satisfy a user request.
Similarly, you should
make it clear
to the user what
you're asking for
and how you intend to use it.
There are two concrete things
that your app should do
if it is going to
use Core Location.
First if you're going to talk
to a server you should attempt
to anonymize those queries
as much as possible.
Let's consider an example.
Say you're writing a
check-in application.
Well, if the user has
tapped the Check-in button,
then it makes sense that you
should send both user identity
information and location
to your server all at once,
since the user clearly wants
your server to know both.
However, if you're writing,
say, a weather application,
then the user probably
doesn't gain much benefit
from your server being able
to associate both
identity and location.
And so the user would
be better served
by an anonymous query
in that instance.
by an anonymous query
in that instance.
Additionally, if you plan on
persisting location information
to disc, you should use
the file protection APIs.
Now this one is relatively
simple,
since file protection is
enabled by default since iOS 8.
However, it is still possible
to create unprotected files,
and so you should make
sure that if you're going
to be persisting location
information, you should not do
so in an unprotected file.
After privacy, power is the
second most important thing
to consider when
using Core Location.
The power cost of using Core
Location is highly variable.
At one extreme, we have Beacon
region monitoring, which is,
for all intents and
purposes, free.
And at the other extreme,
we have continuous
location sessions,
which can drain the user's
battery in just a few hours.
No matter how cool your app is,
if it drains the user's battery
faster than they would expect,
they're not going
to enjoy using it.
Thus, you must design your
app with power in mind.
Sometimes that means sacrificing
accuracy or latency in order
to achieve the power metrics
that your users would expect.
To achieve that, you
must use the right API.
But Core Location
has a lot of APIs.
How do you know which
one is the right one?
I put together a
simple decision tree
that should help guide
you toward the right API.
It's not meant to
capture every possibility,
but it should be enough
to get you started.
The first question to consider
is whether you want the user's
location now, or
sometime in the future.
If you're interested in the
future, then you want to use one
of our background
monitoring APIs.
Either region monitoring,
if you're interested
in a specific location, or visit
monitoring if you're interested
in a specific location, or visit
monitoring if you're interested
in any location that
the user stops at.
If you want to know about
the present, then you want
to use our standard
location service.
Now, there's a lot of
different ways you can use it.
So let's drill into
some specifics.
If you're writing a
fitness application,
then we recommend you use
deferred location updates
in a continuous location
session.
If you're writing a
navigation application,
then you probably want to use
a continuous location session.
If your app is continuously
updating UI,
then you also probably want
to use a continuous
location session.
The final question to consider
is whether your app is recording
a track of the user's location.
If it is, then we would
recommend you use deferred
location updates.
In most other situations,
we would recommend using
the single location API.
You may have noticed
the battery icon
at the bottom of this slide.
These aren't meant to be taken
literally, they're just a guide
to give you a rough idea of how
much power each service uses.
Okay, for authorization,
we highly recommend you use
when-in-use authorization
whenever possible.
Users like knowing that
you can't track them
without their knowledge.
Furthermore, you should
communicate with your users
and make sure they
understand why you're asking
for the authorization
level you are,
and how you intend
to make use of it.
Remember, Core Location
displays a prompt
that includes a usage
description key provided
by your app.
This is an excellent opportunity
to communicate with the user,
but hopefully it's not the
last opportunity you'll take.
Your app should be prepared
to direct users to settings.
Core Location only
displays a limited number
of authorization prompts for
your app, and so at some point,
of authorization prompts for
your app, and so at some point,
if you want your authorization
level changed, users will have
to go to settings
and do it themself.
If you direct your
UI application
to open the UI application, open
settings, URL string constant,
then iOS will display
your apps settings pane.
For Potluck, our sample app,
it looks something like this.
As you can see, the user
is just a few taps away
from changing Potluck's
authorization.
We've seen a lot of developers
get confused by Core Location
and it's threading requirements.
The first thing to remember is
that Core Location requires you
to create your CLLocationManager
on a thread that has a runloop.
When the location manager is
initialized, it will determine
which run loop is associated
with the current thread.
It will then deliver
all delegate callbacks
on that runloop.
Now, for many applications,
the main thread is the
only thread with a runloop.
As such, it is safe to
create your location manager
on the main thread, but
if you do, be careful.
You have to keep your
main thread active
in order to handle UI events.
If you spend a lot of time
processing location information,
then your app will
become unresponsive.
We recommend that you always
interact with location manager,
that is, call its
methods from the thread
that it was created on.
We believe this simplifies
interactions
with location manager.
Let's look at some code.
Here I am requesting
authorization.
Let's suppose I've already added
the necessary usage description
keys to my information
property list.
Here, I'm creating
a location manager,
and I'm calling request
when-in-use authorization.
Unfortunately, this won't work.
See,
the requesWhenInUseAuthorization
method is asynchronous,
and CLLocationManager when it is
deallocated will automatically
tear down any outstanding
authorization prompts,
and so the user probably won't
see the authorization prompt
at all, since the manager
will be deallocated
at the end of the function.
Let's try something
a little different.
If we put it into a
static class property,
then it will certainly
live long enough.
However, this introduces
a new bug.
See, Swift will initialize the
manager property the first time
it's accessed.
And unless we're very careful
and ensure we always access it
from a thread with a runloop,
this could create
a location manager
on a thread without a runloop.
We believe this pattern is error
prone and discourage its use.
One more try.
Here, we are creating
our location manager
as an instance property
on a ViewController.
as an instance property
on a ViewController.
Now, view controllers are always
constructed on the main thread,
and in this instance,
the location manager
will be created along
with the ViewController.
So we are guaranteed that
the location manger will be
constructed on the main thread.
This is the recommended pattern
for creating location managers.
You might also consider
attaching it
to your app delegate instead.
Now since the standard location
service can be the most power
hungry of all of
Core Location's APIs,
it's important to
use it correctly.
First we recommend using
the request location API
whenever possible.
Second, you should ensure
that your desired
accuracy property is set
to the largest value
your app can tolerate.
Generally, more accurate
locations require more power
to create.
As an example, if you request,
say, 100 meter accuracy,
Core Location usually doesn't
need to turn on the GPS in order
to satisfy your location
request.
Keep in mind that Core
Location will give you
or could give you a location
update that is more accurate
than what you requested.
So to say you request a 3
kilometer accuracy location.
This will effectively
ask Core Location
to give you whatever location
is most readily available.
We encourage you to keep
automatic pausing enabled.
We've tuned the automatic
pausing algorithm
to be fairly conservative.
We would be surprised if it
stopped your location session
at a time when the user was
still gaining benefit from it.
As long as you've configured it
correctly, you should be able
to leave it running
all the time.
To configure automatic pausing,
simply set the activity
type property
on your location manager
to the appropriate value.
on your location manager
to the appropriate value.
If you'd like to learn more,
you should consult
our documentation.
Similarly, we recommend leaving
or enabling deferred
location updates.
Deferred location updates allows
Core Location to put the device
into a low power state
and collect location
information passively
and then process it
in large batches.
This can result in a fairly
large power savings compared
to a normal continuous
location session.
If this is all a
little confusing,
and you're not entirely
sure how each
of these settings plays
out, you might want
to consider using the energy
log instrument in Xcode.
This will give you a rough idea
of how much power your
continuous location sessions
are drawing.
Finally, we recommend
that you set the
allowsBackgroundLocationUpdates
property to true only
allowsBackgroundLocationUpdates
property to true only
when you're sure that you want
to begin a background
location session.
We've seen some apps set
it to true unconditionally
and then just stop
their location sessions
when they enter the background,
but this has a negative
side effect.
Here, I've modified Potluck, our
sample app, to do exactly that.
You'll see that when I start
the session and then home out,
there is a blue bar at
the top of the screen
for just a few seconds.
So here I am starting
the session.
Then I hit the home button,
and there is a blue bar
at the top of the screen.
This can be easily avoided
by simply managing your
allowsBackgroundLocationUpdates
property properly.
Now, our monitoring APIs
affect your entire process.
As such, we recommend that
you always interact with them
from a single location manager,
shared by your entire process.
You might want to attach
it to your app delegate.
You might want to attach
it to your app delegate.
Furthermore, our
monitoring APIs will continue
until you tell it to stop.
This is true, even if
you update your app
and remove all references
to Core Location
and stop linking the framework.
So we highly recommend that
whenever your app is launched,
you take a moment and assess
whether you think Core Location
should be doing background
monitoring for your app.
Unless you're sure that at
that time background
monitoring should be running,
you should tell Core
Location to stop monitoring.
This small snippet of code is
all it takes to stop all three
of our background
monitoring APIs.
>> If you're writing an
app for an indoor venue,
you should remember that Core
Location will automatically
enable indoor location
technologies whenever your app--
sorry, whenever the user--
is inside your venue.
sorry, whenever the user--
is inside your venue.
This only happens if your
venue has been surveyed.
If you'd like your
venue to get surveyed,
go to mapsconnect.apple.com
to learn more.
Beacon region monitoring is
a highly versatile technology
that can be used in all
sorts of problem domains,
but we think it pairs especially
well with indoor scenarios.
It complements indoor
location very well.
Beacon region monitoring allows
your app to detect proximity
to landmarks that you've
established inside the venue.
Indoor location allows you to
display the user's location
on a map, and help them navigate
from one location to another.
On watchOS, you should remember
that Core Location will
automatically leverage the
iPhone if it's nearby.
Let us handle talking
to the iPhone
Let us handle talking
to the iPhone
and using it to compute
locations.
Furthermore, we've seen a lot
of apps request always
authorization on watchOS,
even though what they are
doing could be accomplished
with when-in-use authorization.
If you're thinking of using
always authorization on watchOS,
we would encourage you
to take a second look
at when-in-use authorization.
For watchOS 3, we are making
startUpdatingLocation available
on watchOS.
However, most apps would still
probably be better served
by requestLocation.
There is an exception, though.
In watchOS 3, we've
made background
on watch possible
for fitness purposes.
So if you're looking at
creating a workout application,
we believe
that startUpdatingLocation is
the perfect API or you to use.
For macOS, we only support
always authorization.
For macOS, we only support
always authorization.
Furthermore, Core Location will
automatically display a prompt
when you attempt to access
location information.
You don't need to call
requestAlwaysAuthorization
on macOS.
Since Macs don't tend to
move around very much,
we believe that requestLocation
is usually the API you want
to use on macOS.
For tvOS, you have got
three powerful APIs,
Single Location,
Geocoding and MapKit.
Using these APIs, you've
got everything you need
to create a great location
aware experience on Apple TV.
But be extra careful with
any information vended
to your application
through Core Location;
tvOS devices usually
live in a user's home,
and the user's home is among the
most sensitive information you
can get from Core Location.
You should treat
that information
with the respect it deserves.
That brings us to the
end of our session today.
There are four things I want
you to remember as you leave.
First, you must respect
the user's privacy.
Part of this is communicating
with the user
and making sure they understand
what you're asking for
and how you intend to use it.
Second, conserving power
is an essential part
of using Core Location.
Sometimes you have to sacrifice
accuracy and latency in order
to create the experience
your users would expect,
while still having the power
metrics your users would expect.
To do that, you have to make
sure you use the correct Core
Location API for
your problem domain.
Similarly, make sure you use
when-in-use authorization
Similarly, make sure you use
when-in-use authorization
whenever you can.
If you're having a hard
time getting started
with Core Location, I
recommend you take a look
at Potluck, our sample app.
We updated it this
year for Swift 3,
so it's looking better
than ever.
If you'd like to learn more
you can view our supplementary
material online or check out
one of these related sessions.
With that, thank
you for your time.
Enjoy the rest of WWDC.
[ Applause ]