iOS Location Services for the rest of us

CocoaheadsSKG

Dimitri James Tsiflitzis

Core Location

  • The Core Location framework lets you determine the current location or heading associated with a device.

 

  • The framework uses the available hardware to determine the user’s position and heading.

 

  • You can also use it to define geographic regions and monitor when the user crosses the boundaries of those regions.

Requesting Permission

if CLLocationManager.authorizationStatus() == .NotDetermined {
    manager.requestAlwaysAuthorization()
}

// OR

if CLLocationManager.authorizationStatus() == .NotDetermined {
    manager.requestWhenInUseAuthorization()
}
func locationManager(manager: CLLocationManager,
                     didChangeAuthorizationStatus status: CLAuthorizationStatus)
{
    if status == .AuthorizedAlways || status == .AuthorizedWhenInUse {
        manager.startUpdatingLocation()
        // ...
    }
}

Technologies it uses

  • GPS: Reads microwave for satellites to determine location
  • Cell phone triangulation: Determine current location by calculation based on the cell towers currently in the phones range
  • Wifi: IP + referencing a database of WiFi points. Who knows

Enabling in your app

Initialisation

let manager = CLLocationManager()
if CLLocationManager.locationServicesEnabled() {
    manager.startUpdatingLocation()
}

Descriptive String (rejection alert)

In your app .plist the values assigned to the

 

  • NSLocationWhenInUseUsageDescription 
  • NSLocationAlwaysUsageDescription

 

These keys are now mandatory.

Descriptive String (rejection alert)

Requesting multiple permissions

switch CLLocationManager.authorizationStatus() {
    case .AuthorizedAlways:
        // ...
    case .NotDetermined:
        manager.requestAlwaysAuthorization()
    case .AuthorizedWhenInUse, .Restricted, .Denied:
        let alertController = UIAlertController(
            title: "Background Location Access Disabled",
            message: "Please open this app's settings and set location access to 'Always'.",
            preferredStyle: .Alert)

        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
        alertController.addAction(cancelAction)

        let openAction = UIAlertAction(title: "Open Settings", style: .Default) { (action) in
            if let url = NSURL(string:UIApplicationOpenSettingsURLString) {
                UIApplication.sharedApplication().openURL(url)
            }
        }
        alertController.addAction(openAction)

        self.presentViewController(alertController, animated: true, completion: nil)
}

Requesting multiple permissions

Backwards compatibility

This has been the location framework since iOS 8.0

 

tl;dr don't worry about it

Indoor location tracking

  • The ground floor is 0
  • A CLLocation object returned by a CLLocationManager may include a floor property
class CLFloor : NSObject {
    var level: Int { get }
}
  • A CLVisit object encapsulates information about interesting places that the user has been.

 

  • Visit objects are created by the system and delivered by the CLLocationManager object to its delegate after you start the delivery of events.

 

  • The visit includes the location where the visit occurred and information about the arrival and departure times as relevant.

 

  • You do not create visit objects directly, nor should you subclass CLVisit

Handling visits

Handling visits

manager.startMonitoringVisits()

func locationManager(manager: CLLocationManager, didVisit visit: CLVisit!) {
    if visit.departureDate.isEqualToDate(NSDate.distantFuture()) {
        // User has arrived, but not left, the location
    } else {
        // The visit is complete
    }
}
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
}

Request Quick Location Updates for Energy Efficiency

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    // Get a fix on the user's location
    ...
        
        // Stop location updates
        self.locationManager.stopUpdatingLocation()
}

Stop Location Services When You Aren’t Using Them

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()
}

Reduce Accuracy of Standard Location Updates Whenever Possible


extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
extern const CLLocationAccuracy kCLLocationAccuracyBest;
extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;

Reduce Accuracy of Standard Location Updates Whenever Possible

On devices with GPS hardware, you can let the location manager defer the delivery of location updates when your app is in the background.

Defer Location Updates When Running in the Background Energy Efficiency

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()
}

Defer Location Updates When Running in the Background Energy Efficiency

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
}

Defer Location Updates When Running in the Background Energy Efficiency

NOTE

The monitoring techniques described below provide entry and exit notifications only. To determine the user’s actual location when a notification is received, you must call the requestLocation: or startUpdatingLocation: method of the location manager object. These monitoring techniques also require an authorization status of kCLAuthorizationStatusAuthorizedAlways.

Restrict Location Updates to Specific Regions or Locations

Restrict Location Updates to Specific Regions or Locations

let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: coordinate.latitude,
            longitude: coordinate.longitude), radius: regionRadius, identifier: title)
        locationManager.startMonitoringForRegion(region)


func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
    showAlert("enter \(region.identifier)")
}
 
// 2. user exit region
func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
    showAlert("exit \(region.identifier)")
}

Significant location change monitoring

NOTE

These monitoring techniques also require an authorization status of kCLAuthorizationStatusAuthorizedAlways.

Significant location change monitoring

// Somewhere

[locationManager startMonitoringSignificantLocationChanges];

// didFinishLaunching

 if([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
    
        locationManager                                    = [[CLLocationManager alloc] init];
        locationManager.desiredAccuracy                    = kCLLocationAccuracyBestForNavigation;
        locationManager.activityType                       = CLActivityTypeAutomotiveNavigation;
        locationManager.allowsBackgroundLocationUpdates    = YES;
        locationManager.distanceFilter                     = kCLDistanceFilterNone;
        locationManager.pausesLocationUpdatesAutomatically = NO;
 }

// location manager delegate

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

}

Significant location change monitoring

  • Significant-change location updates wake the system and your app once every 15 minutes, at minimum, even if no location changes have occurred.
  • Significant-change location updates run continuously, around the clock, until you stop them.

Significant location change monitoring

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.

Ευχαριστούμε

iOS Location Services for the rest of us

By tsif

iOS Location Services for the rest of us

  • 225