2011 • 21:31
Learn how to choose the right location service for your app, and how to add overlays to your maps.
Speaker: Vicki Murley
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
I'm Vicki Murley, the Safari Technologies Evangelist at Apple, and in this presentation, I'm going to show you how to enhance your app with location and map information. You'll learn the basics of fetching a location, and how to leverage the latest features in iOS so that your app can track location updates continuously, detect significant location changes, and display additional information on maps with overlays. Let's get started. So in everyday life, people want to know where they, and the items they're interested in, exist in a geographic context.
For example, if you're thinking about buying a house, location is a key piece of information. You typically start with the location and say, "I want to live there." When you go to a stadium, you might be thinking, "How close to the action am I going to be?" Location is key in this situation as well, and so are other circumstances like distance and proximity.
You might just want to know the quickest route away from the action. Furthermore, the world is getting smaller. We travel more, we interact more with people all around the globe. And we always have our iPhone in our pocket. We use it for communicating with friends, for discovering places, for taking notes, and for saving memories.
And the iPhone always knows where it is. With this knowledge of location, of what's around, apps help keep us connected to the surrounding world. They can tell us what's around, who's around, how to get there, in many different situations: while commuting, while shopping, visiting new places, meeting friends, or while playing games.
And it's not only in our spare time. Even at work, doctors, lawyers, builders, small businesses, they can all take advantage of location and the powerful features that location-aware apps can provide. Location is all about knowing where you are, what's around, and how to get from where you are to whatever is interesting.
So let's see how location awareness can live in your app. First of all, location can have a big visual impact, like when it's used as the main metaphor or the central element of the UI in your app. This is one possible visualization of location, a point on a map, as in a restaurant guide, or maybe even a social networking app.
Or, instead of showing your location in real time, you might want to use location to add information that's used later on. For example, location can be embedded in the photos that you take, silently behind the scenes, then later the location of each photo can be shown on a map to give that photo a much better context. Alternately, location can be less dominant, less visible in your UI, but still augment the experience. Even if you don't show a map in your app, location information can still be very valuable.
That's the case in Foursquare, where a distance indicator shows how far away a place is. Or in Google Places. Notice how Google Places adds an extra piece of information: which direction a place is. Very convenient. And again, it really augments the experience of browsing a list of places.
Another example is Apple's own Maps app. Something as simple as a small thumbnail map enriches the content, and it provides context. Lastly, location can facilitate actions by doing something behind the scenes. No maps, no indicators, just functionality which uses location in a subtle way to make the app easier and faster to use. For example, in the BART app, location is used to provide a default subway station as your starting point, so that you don't have to type this information in yourself. The WeatherPro app detects the city you're in so that you can easily add that city to your favorites.
Or, going back to the four-square example, notice how location is used to sort items by distance so that the most relevant items are at the top and less scrolling is required. That's a common but powerful way of facilitating a better user experience with location. These are the three ways that location awareness can be expressed in your app. Now let's look at the nuts and bolts and see how your iOS device retrieves location information.
Location services are provided by the Core Location Framework, which uses multiple sensors for obtaining information about the user's location and device orientation in space. Maps are provided by the MapKit Framework, which supports both the display and annotation of maps. So let's get started by looking at Core Location.
There are three techniques that iOS uses for obtaining a device's position: cell-based triangulation, Wi-Fi triangulation, and GPS. Cell-based triangulation provides an accuracy between 500 and 3,000 meters. It requires a data connection but works well indoors, and the accuracy is better in urban areas where cell density might be greater.
Wi-Fi requires a data connection and also works well indoors. It has an accuracy between 50 and 250 meters, and can be just as good or better than GPS, especially in indoor environments. Finally, GPS can also be used to obtain the position of an iOS device. It doesn't require a data connection, and it provides accuracy in the range of 10 to 100 meters.
So as I mentioned, each location technique has its own accuracy and has specific requirements in terms of power and time. For example, GPS is the most accurate, but it also requires the most power and it takes the most time to get an accurate fix on the position. While we as developers tend to always think of precision first, users are really concerned about power. You want them to use your app as much as possible, so the lower your power consumption, the better.
Another thing to consider is availability. 3G iPads and iPhones can use all three positioning methods, but what about an iPod Touch? What about a Mac running Snow Leopard? At first glance, it might make sense to focus your application on devices that support GPS positioning, but there are some cases, for example in indoor environments, when Wi-Fi can locate users even better than GPS in terms of both time and accuracy.
And the great thing about cell-based triangulation is that it's available pretty much anywhere, as long as there's a signal. The takeaway here is really to think through the usage scenarios for your app, and decide which type of location retrieval is sufficient, instead of just choosing GPS by default.
So how do you use Core Location in your app? At the base level, you have your app with a delegate object and the Core Location framework itself. The CL Location Manager object is the object that you're going to interact with. So you can request location updates by calling Start Updating Location.
The way location information is reported to your app is totally asynchronous. When a position comes in, your delegate, which conforms to the CL Location Manager delegate protocol, will call the Location Manager Did Update to Location from Location callback. As the user moves, the framework repeatedly detects new positions.
You also need to configure the location manager. When you're doing this, the first thing you need to consider is what accuracy you require. This is an indication of how precise a measurement you're going to need. It's measured as the maximum difference you're willing to accept between the detected position and where the user actually is in meters. You should also specify a distance filter. Normally, you don't need to get a new location every time the user moves a tiny bit, but only when the user moves significantly. By specifying a distance filter that's reasonable for your application, you can save system resources such as power.
You also might want to check if location services are even enabled before you call Start Updating Location. So if your attempt to fetch a location fails, there are two key errors that you might get: KCL Error Location Unknown or KCL Error Denied. KCL error location unknown is reported when a location cannot be determined, and this is a temporary error. Maybe the user has temporarily lost network connectivity if they've gone underground on the subway or they're in a remote area.
KCL Error Denied is reported when the user has explicitly denied location services for your application, and they can do this in a few different ways. The first way that users can deny location services is by tapping Don't Allow on this dialog. It pops up the very first time that your application requests a location, and if a user taps Don't Allow, then that decision sticks.
It's important to provide a good description of why your app needs location, or how it's going to use this information. You can communicate this information to users via the Purpose property in your code. There are also switches and settings that control access to location information. There's a global switch, which enables or disables location services for all apps. And there's a list of switches for each individual app that has requested location services. In this list of apps, sometimes you'll see this location arrow icon. It indicates that the app has requested a location in the last 24 hours.
Keep in mind that users can toggle these switches at any time, even when your application is running, and then your app will receive the KCL error denied error code. So now let's talk about a few best practices for using the Core Location Framework. Remember that sometimes certain environments can make positioning difficult. If you receive a KCL Error Location Unknown error, call Stop Updating Location and try to fetch the location again later, when conditions may have changed.
Also, you might be fetching location information until you receive a location that has the accuracy that you're looking for. Since positioning can be difficult in certain environments, your desired accuracy might never actually be obtained, so be sure to put a limit on the amount of time you spend fetching location information and call Stop Updating Location once that time period expires.
You should also always remember to call Stop Updating Location when your app doesn't actively require a location. Doing so will really save a lot of power for users. For example, if your application uses location only in a specific view or tab, then you don't want to keep the location manager running all the time, because maybe the user won't even go into that section of your app.
In that case, you want to start and stop updating location when the user enters and exits that section of your UI. To double check that you're doing things properly, you can look at the status bar and make sure that the location indicator is not active when your app doesn't actively require a location. Finally, always remember to have a Plan B. You should always provide a fallback experience in your app in cases where a location or map tiles may not be available.
So far, we've been talking about a question and answer. You might be wondering what happens if your app doesn't have a location, but what about tracking location as the device moves? Your app might require tracking location all the time, maybe even when your app has been switched to the background.
So I want my app to keep tracking location as the device moves, no matter what I'm doing, whether the app is in the foreground or the background. How can I do this? Well, Apple has introduced support for what we call continuous location applications. All you have to do is add this one key to your Info.plist file, and once that's set, if your application calls start updating location and then goes into the background, it will keep running as long as you keep updating the location. Since this is an expensive operation, you should only use this when it provides an immediate, tangible benefit to the user.
There are other cases when we don't want precise location tracking all the time. Suppose we're traveling, and every once in a while we take a photo or record a note, and we want to store the location for each of those. To do this, we can use a technique which only notifies us and wakes up our app when a significant location change has occurred. In this case, cell-based triangulation is generally used.
For significant location changes, the location is calculated when the device switches cell towers, or when other applications use location services. So when one of these significant location changes occurs, your application will be launched in the background to retrieve that location. While the accuracy of significant location changes is generally similar to cell-based triangulation, if some other app in the system is asking for a more precise location and causes GPS to be used, you'll get this more accurate location for free.
So how do you implement this in your app? This slide probably looks familiar. You've seen it before when I was explaining how to start up location services. All you really need to do is replace this call, "Start updating location," with one that's called "Start monitoring significant location changes." Once you call that, you'll get the same delegate method, no matter whether your app is frontmost or suspended in the background. If it is in the background, your app will resume so that your delegate method can be executed.
There are times that a very specific location is all that's really important, when a user gets close to, or goes far from, a specific place. For this type of scenario, there is a technique called Region Monitoring. While in the background, we use cell triangulation, but we only notify you when the user is close to that specific location.
Implementing this functionality in your app is really simple. The first thing you need to do is create what's called a CLRegion object. It's defined by a center and a radius, how large you want it to be, and an identifier. Next, you call startMonitoringForRegion, passing in that region. At this point, your delegate will receive one of two callbacks: Location Manager Did Enter Region or Location Manager Did Exit Region. The great thing about these services is that they can be used even if your application is not running.
If your app moves to the background, location services are still tracking the user and determining the location. The great thing about these services is that they can be used even if your application isn't running. If your application hasn't been launched or if your app moves to the background, the location service is still tracking the user and determining the location.
Since your app can be launched in the background, it's worth mentioning the MVC paradigm around which all iOS applications are based. Generally, you've got your model, which is your data, the view objects, which control how the data appears on screen, and the controller that sits in between. Now in a lot of apps, the location manager is actually used by view controllers. But when the app is launched in the background, the view hierarchy does not get set up.
And so if you instantiate a location manager object as part of your view controller, it will never be created and you will never get the location events. When your app is launched in the background, your app delegate is sent this message. There's an options dictionary which can tell you whether the app was launched because of a location event.
Note that if your application is killed in the background and the user launches it before the next event, this key won't be present. So generally, you're going to want to use an application-wide controller to instantiate a location manager object. You'll set the delegate to such controller in order for the location manager to be able to deliver messages, and that's it.
What are some best practices for using the Core Location Framework in this way? For instance, you might want to use the UI Device APIs to decide what functionality to enable in the background. Based on the battery charge level, you can decide whether to keep monitoring location changes, or even modify the level of accuracy that you require. Now let's move on to talking about what's new in MapKit.
The MapKit framework provides standard views that you can incorporate into your application to display information tied to a specific geographic point. MapKit has always provided support for annotations, which represent a single point on the map. New in iOS 4.0, MapKit also provides a way to add overlays to maps.
MapKit overlays are great because they'll pan and zoom along with the rest of the map content as the map is manipulated by the user. This provides a seamless and polished experience as if the overlay itself is part of the map. There are four different types of overlays available in MapKit.
The first type of overlay is a circle. You can create and draw circles with the MKCircle and MKCircleView classes, and use these to highlight a circular region on a map. For instance, maybe you want to show something like signal strength or the accuracy of a retrieved location. You can also draw lines on a map as an overlay, using MKPolyline and MKPolylineView. Polygons are the third type of overlay supported in MapKit. You can use MKPolyline and MKPolylineView to highlight a specific area on a map, and you can even mask out portions of the polygon by specifying one or more interior polygons.
And finally, you can create your own custom type of overlay. So you can really depict any type of data that you want as an overlay on a map. So how do I add an overlay to my map? Well, if you've programmed with MapKit before, this probably sounds familiar, because adding overlays to the map is a lot like adding annotations. There's really just two steps. The first step is to add your overlay model object to the map, and after that, you display the overlay by providing the corresponding view from the delegate.
Here's what the code for that might look like. Here in ViewDidLoad, we're creating our overlay object. It's just a circle with a CoreLocation2D coordinate as its center, and it has a radius of 200. We add our circle overlay to the map by passing it to the Add Overlay method.
But just adding the model to the map doesn't necessarily draw the overlay, which is good because the region of the map with your overlay might not even be on screen at this point. When MapKit detects that the region that contains your overlay is coming into view and needs to be drawn, you'll get a callback on your MapView delegate, ViewForOverlay.
When you receive this delegate callback, ViewForOverlay, that's when you're going to create the view. Since we have an MKCircle overlay, we're going to create an MKCircle view, and here we're customizing the look of that circle just a little bit by adding a red stroke around the circle, and filling the circle with red as well, with a 40% opacity so that users can see through it to the map. So there you have it. Now you have the resources you need to enhance your existing app with location information, or even build an entirely new app around the location services provided in iOS. I'm really looking forward to seeing what you come up with.