Reduce Location Accuracy and Duration
Using location-based information in your app is a great way to keep the user connected to the surrounding world. However, improper or unnecessary use of location can prevent the device from sleeping, keep location hardware powered up, drain the user’s battery, and create a poor user experience. Follow best practices to optimize use of location services for energy efficiency.
Request Quick Location Updates
If your app just needs a quick fix on the user’s location, it’s best to call the requestLocation
method of the location manager object, as shown in Listing 14-1. Doing so automatically stops location services once the request has been fulfilled, letting location hardware power down if not being used elsewhere. Location updates requested in this manner are delivered by a callback to the locationManager:didUpdateLocations:
delegate method, which you must implement in your app.
Objective-C
-(void)viewDidLoad {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
}
-(void)getQuickLocationUpdate {
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Request a location update
[self.locationManager requestLocation];
// Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Process the received location update
}
Swift
override func viewDidLoad() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
}
func getQuickLocationUpdate() {
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Request a location update
self.locationManager.requestLocation()
// Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Process the received location update
}
Stop Location Services When You Aren’t Using Them
With the exception of navigation apps that offer turn-by-turn directions, most apps don’t need location services to be on all the time. Turn location services on only when they’re needed. Then, leave them on just long enough to get a location fix and turn them off again. Unless the user is in a moving vehicle, the current location shouldn’t change frequently enough to be an issue. You can always start location services again later if you need another update.
To stop standard location updates, call the stopUpdatingLocation
method of the location manager object. See Listing 14-2.
Objective-C
-(void)getLocationUpdate {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Start location updates
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Get a fix on the user's location
...
// Stop location updates
[self.locationManager stopUpdatingLocation];
}
Swift
func getLocationUpdate() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Start location updates
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Get a fix on the user's location
...
// Stop location updates
self.locationManager.stopUpdatingLocation()
}
Reduce Accuracy of Standard Location Updates Whenever Possible
Standard location updates let you specify a degree of accuracy ranging from a few meters to a few kilometers by setting the desiredAccuracy
property of the location manager object, as shown in Listing 14-3. Requesting higher accuracy than you need causes Core Location to power up additional hardware and waste power for unnecessary precision. Unless your app really needs to know the user’s position within a few meters, don’t set the accuracy level to best (kCLLocationAccuracyBest
) or nearest ten meters (kCLLocationAccuracyNearestTenMeters
). Also, be aware that Core Location typically provides more accurate data than you have requested. For example, when specifying an accuracy level of three kilometers (kCLLocationAccuracyThreeKilometers
), you may receive accuracy within a hundred meters or so.
Objective-C
-(void)getLocationUpdate {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Set an accuracy level. The higher, the better for energy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
// Start location updates
[self.locationManager startUpdatingLocation];
}
Swift
func getLocationUpdate() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Set an accuracy level. The higher, the better for energy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
// Start location updates
self.locationManager.startUpdatingLocation()
}
Stop Location Updates if Accuracy Doesn’t Match Expectations
If your app isn’t receiving updates with the expected level of accuracy, your app should examine the updates it is receiving and determine whether accuracy is improving or staying about the same over time. If accuracy isn’t improving, it’s possible that the desired level of accuracy simply isn’t available at the moment. In this case, stop location updates and try again later so your app doesn’t continuously cause location hardware to draw power.
Auto-Pause and Specify an Activity Type When Receiving Location Updates in the Background
If your iOS app must continue monitoring location while it’s in the background, enable background mode in the Xcode Project > Capabilities pane. Select the checkbox for Location updates, as shown in Figure 14-1.
In iOS 9 and later, regardless of deployment target, you must also set the allowsBackgroundLocationUpdates
property of the location manager object to YES
true
in order to receive background location updates. By default, this property is NO
false
, and it should remain this way until a time when your app actively requires background location updates.
Make sure the location manager object’s pausesLocationUpdatesAutomatically
property is set to YES
true
to help conserve power.
Set the activityType
property to let Core Location know what type of location activity your app is performing at a given time—for example, if your app is performing fitness tracking or automotive navigation. See CLActivityType
for a list of activity types.
Specifying these settings helps the location manager determine the most appropriate time to perform location updates. For example, background location updates may be auto-paused if the system determines that the user isn’t moving.
See Listing 14-4.
Objective-C
-(void)startBackgroundLocationUpdates {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Set an accuracy level. The higher, the better for energy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
// Enable automatic pausing
self.locationManager.pausesLocationUpdatesAutomatically = YES;
// Specify the type of activity your app is currently performing
self.locationManager.activityType = CLActivityTypeFitness;
// Enable background location updates
self.locationManager.allowsBackgroundLocationUpdates = YES;
// Start location updates
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Perform location-based activity
...
// Stop location updates when they aren't needed anymore
[self.locationManager stopUpdatingLocation];
// Disable background location updates when they aren't needed anymore
self.locationManager.allowsBackgroundLocationUpdates = NO;
}
Swift
func startBackgroundLocationUpdates() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Set an accuracy level. The higher, the better for energy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
// Enable automatic pausing
self.locationManager.pausesLocationUpdatesAutomatically = true
// Specify the type of activity your app is currently performing
self.locationManager.activityType = CLActivityTypeFitness
// Enable background location updates
self.locationManager.allowsBackgroundLocationUpdates = true
// Start location updates
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Perform location-based activity
...
// Stop location updates when they aren't needed anymore
self.locationManager.stopUpdatingLocation()
// Disable background location updates when they aren't needed anymore
self.locationManager.allowsBackgroundLocationUpdates = false
}
Defer Location Updates When Running in the Background
On supported devices with GPS hardware, you can let the location manager defer the delivery of location updates when your app is in the background. For example, a fitness app that tracks the user’s location on a hiking trail can defer updates until the user has moved a certain distance or a certain period of time has elapsed. Then, it can process the updates all at once. You can use deferredLocationUpdatesAvailable
to determine if a device supports deferred location updates.
To defer updates, call the location manager object’s allowDeferredLocationUpdatesUntilTraveled:timeout:
method and pass it a distance and time that may elapse before the next location update is received. This method is typically called in the locationManager:didUpdateLocations:
delegate method in order to defer again, if appropriate, when a deferred location update is received.
When a deferred location update is received, the locationManager:didFinishDeferredUpdatesWithError:
delegate method is also called, and your app can use this as an opportunity to adjust behavior accordingly—such as increasing or decreasing the deferral distance and time—for the next update. See Listing 14-5.
Objective-C
-(void)startHikeLocationUpdates {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Specify the type of activity your app is currently performing
self.locationManager.activityType = CLActivityTypeFitness;
// Start location updates
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Add the new locations to the hike
[self.hike addLocations:locations];
// Defer updates until the user hikes a certain distance or a period of time has passed
if (!self.deferringUpdates) {
CLLocationDistance distance = self.hike.goal - self.hike.distance;
NSTimeInterval time = [self.nextUpdate timeIntervalSinceNow];
[self.locationManager allowDeferredLocationUpdatesUntilTraveled:distance timeout:time];
self.deferringUpdates = YES;
} }
-(void)locationManager:(CLLocationManager *)manager
didFinishDeferredUpdatesWithError:(NSError *)error {
// Stop deferring updates
self.deferringUpdates = NO;
// Adjust for the next goal
}
Swift
func startHikeLocationUpdates() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Specify the type of activity your app is currently performing
self.locationManager.activityType = CLActivityTypeFitness
// Start location updates
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Add the new locations to the hike
self.hike.addLocations(locations)
// Defer updates until the user hikes a certain distance or a period of time has passed
if (!deferringUpdates) {
distance: CLLocationDistance = hike.goal - hike.distance
time: NSTimeInterval = nextUpdate.timeIntervalSinceNow()
locationManager.allowDeferredLocationUpdatesUntilTraveled(distance, timeout:time)
deferringUpdates = true;
} }
func locationManager(manager: CLLocationManager, didFinishDeferredUpdatesWithError error: NSError!) {
// Stop deferring updates
self.deferringUpdates = false
// Adjust for the next goal
}
Restrict Location Updates to Specific Regions or Locations
Some apps don’t need to receive continuous location updates, and just need to know when the user is within a certain distance of a location. For example, a grocery app may display new coupons whenever the user nears the store. There are several Core Location APIs that can keep your app informed.
Region and Beacon Monitoring
Core Location provides two methods for detecting a user’s entry to and exit from specific regions.
Geographical region monitoring provides entry and exit notifications for a specified location on the Earth.
Beacon monitoring provides entry and exit notifications when the user is within range of low-powered Bluetooth devices that are advertising iBeacon information.
For detailed information on using these techniques, see Region Monitoring and iBeacon in Location and Maps Programming Guide.
Visit Monitoring
Visit monitoring allows an app to receive entry and exit notifications for specific locations the user visits frequently or for long periods of time such as home, work, or a favorite coffee shop.
To begin monitoring for visits, assign a delegate to the location manager object and call its startMonitoringVisits
method. Note that calling this method enables all visit updates in your app, not just ones for the current delegate. When enabled, visit events are delivered to the locationManager:didVisit:
method of the delegate. If your app isn’t running when a visit event is delivered, your app is relaunched automatically. When visit location updates are no longer required, call stopMonitoringVisits
, as shown in Listing 14-6.
Objective-C
-(void)startVisitMonitoring {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestAlwaysAuthorization];
// Start monitoring for visits
[self.locationManager startMonitoringVisits];
}
-(void)stopVisitMonitoring {
[self.locationManager stopMonitoringVisits];
}
-(void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit {
// Perform location-based activity
...
}
Swift
func startVisitMonitoring() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
// Request location authorization
self.locationManager.requestAlwaysAuthorization()
// Start monitoring for visits
self.locationManager.startMonitoringVisits()
}
func stopVisitMonitoring() {
self.locationManager.stopMonitoringVisits()
}
func locationManager(manager: CLLocationManager, didVisit visit: CLVisit!) {
// Perform location-based activity
...
}
Register for Significant-Change Location Updates Only as a Last Resort
If GPS-level accuracy isn’t critical for your app, you don’t need continuous tracking, and region or visit monitoring isn’t more appropriate for your app, you can use the significant-change location service instead of the standard one.
To start significant-change location updates, call the startMonitoringSignificantLocationChanges
method of the location manager object. When you’re done, call stopMonitoringSignificantLocationChanges
, as shown in Listing 14-7.
Objective-C
-(void)startSignificantChangeLocationUpdates {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestAlwaysAuthorization];
// Start significant-change location updates
[self.locationManager startMonitoringSignificantLocationChanges];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
// Perform location-based activity
...
// Stop significant-change location updates when they aren't needed anymore
[self.locationManager stopMonitoringSignificantLocationChanges];
}
Swift
func startSignificantChangeLocationUpdates() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
// Request location authorization
self.locationManager.requestAlwaysAuthorization()
// Start significant-change location updates
self.locationManager.startMonitoringSignificantLocationChanges()
}
func locationManager(manager: CLLocationManager, didFinishDeferredUpdatesWithError error: NSError!) {
// Perform location-based activity
...
// Stop significant-change location updates when they aren't needed anymore
self.locationManager.stopMonitoringSignificantLocationChanges()
}
Restrict UI When Playing Full-Screen Video
Copyright © 2018 Apple Inc. All rights reserved. Terms of Use | Privacy Policy | Updated: 2016-09-13