SDK

Location Services

In this page you'll dive deeper into functionality like using GPS signals to get the user's location or monitor their visits to regions and proximity to BTLE devices. These services will bring a new level of contextuality to your app, allowing you to create geo-triggers to send notifications or categorize users based on their location behaviour.

Tracking a user location in iOS will require the user's authorization, this means that your app must declare usage description texts explaining why it needs to track location. For older versions of iOS you may optionally declare the key NSLocationUsageDescription in your app's .plist file. In iOS8 and higher, is it mandatory the use of the key NSLocationAlwaysUsageDescription. In iOS 11 a new permission was introduced and you are required to include both NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationWhenInUseUsageDescription in your app's .plist file. Bottom line if you are supporting iOS 7 and up you'll need to include the following in your app's .plist file:

ios location privacy plist entries

Make sure you provide a text that best describes why and how you are going to use the user’s location. This text will be displayed to the user the first time you request the use of location services. Users are more likely to trust your app with location data if they understand why you need it.

Location Updates

Location services can only be requested after a successful device registration. To make sure this happens correctly, the best place to request location services is right after a device registration:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

    [[NotificarePushLib shared] registerDevice:deviceToken completionHandler:^(NSDictionary *info) {

        ...more code

        //Device is regsitered, here it's safe to start requesting location services
        [[NotificarePushLib shared] startLocationUpdates];

        ...more code

    } errorHandler:^(NSError *error) {
        //Handle error
    }];

}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    NotificarePushLib.shared().registerDevice(deviceToken, completionHandler: {(_ info: [AnyHashable: Any]) -> Void in

        ...more code

        //Device is regsitered, here it's safe to start requesting location services
        NotificarePushLib.shared().startLocationUpdates()

        ...more code

    }, errorHandler: {(_ error: Error?) -> Void in
        //Handle error
    })
}

The first time this is requested, it will prompt the user with a permission dialogue. If the user agrees to share location with your app, Notificare will automatically start monitoring significant location changes (roughly every 500m/1,640ft). It will also start monitoring for the nearest regions and beacons you might have created in our dashboard or API. This is basically all it takes to use location services, at this point you should be able to manage all your regions, geo-triggers, beacons and send geo-targeted notifications through our dashboard or API.

Location Services Delegates

In order for you to update your app's UI, react programmatically to location updates or any other custom implementation you might want to add, you should implement the following delegates. Please note that the implementation of these delegates is optional and simply using the dashboard or API to create interactions using location should be enough to create engaging experiences.

This delegate will be triggered whenever you start tracking location. When this delegate is triggered, it is possible to request the authorization status for location services:

- (void)notificarePushLib:(NotificarePushLib *)library didReceiveLocationServiceAuthorizationStatus:(NSDictionary *)status{
    if([[NotificarePushLib shared] checkLocationUpdates]){
        NSLog(@"Location Services enabled: %@", status);
    }
}
func notificarePushLib(_ library: NotificarePushLib, didReceiveLocationServiceAuthorizationStatus status: [AnyHashable: Any]) {
    if NotificarePushLib.shared().checkLocationUpdates() {
        print("Location Services enabled: \(status)")
    }
}

The following delegate will be triggered if locations services could not be started. Typically you can use this delegate to retry again in case it's a network related error or find out why your app is incorrectly configured to use location services:

- (void)notificarePushLib:(NotificarePushLib *)library didFailToStartLocationServiceWithError:(NSError *)error{

    //Handle error

}
func notificarePushLib(_ library: NotificarePushLib, didFailToStartLocationServiceWithError error: Error?) {

    //Handle error

}

This following delegate will be called when location updates are received. It will contain an array of one or more CLLocation objects. This array always contains at least one object representing the current location. If updates were deferred or if multiple locations arrived before they could be delivered, the array may contain additional entries. The objects in the array are organized in the order in which they occurred. Therefore, the most recent location position is at the end of the array.

- (void)notificarePushLib:(NotificarePushLib *)library didUpdateLocations:(NSArray *)locations{
    //Handle locations
}
func notificarePushLib(_ library: NotificarePushLib, didUpdateLocations locations: [Any]) {
    //Handle locations
}

If you've created Geo-Zones in Notificare, you may want get information of the regions being monitored or any events and errors that might occur. This will display all the regions that started being monitored:

- (void)notificarePushLib:(NotificarePushLib *)library didStartMonitoringForRegion:(CLRegion *)region{
    //Handle region
}
func notificarePushLib(_ library: NotificarePushLib, didStartMonitoringFor region: CLRegion) {
    //Handle region
}

You can also get the information if Geo-Zones failed to be monitored. This could be happen because there is a poor cell reception or any kind of GPS errors:

- (void)notificarePushLib:(NotificarePushLib *)library monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error{
    //Handle error
}
func notificarePushLib(_ library: NotificarePushLib, monitoringDidFailFor region: CLRegion, withError error: Error?) {
    //Handle error
}

You can also track Geo-Zones states by implementing the following delegate:

- (void)notificarePushLib:(NotificarePushLib *)library didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
    switch (state) {
        case CLRegionStateInside:
        break;
            case CLRegionStateOutside:
        break;
            case CLRegionStateUnknown:
        break;
            default:
        break;
    }
}
func notificarePushLib(_ library: NotificarePushLib, didDetermineState state: CLRegionState, for region: CLRegion) {
    switch state {
        case .inside:
            break
        case .outside:
            break
        case .unknown:
            break
        default:
            break
    }

}

Finally, you can also be informed whenever the user enters or leaves a certain region:

- (void)notificarePushLib:(NotificarePushLib *)library didEnterRegion:(CLRegion *)region{
    //User is entered a region
}

- (void)notificarePushLib:(NotificarePushLib *)library didExitRegion:(CLRegion *)region{
    //User is left a region
}
func notificarePushLib(_ library: NotificarePushLib, didEnter region: CLRegion) {
    //User is entered a region
}

func notificarePushLib(_ library: NotificarePushLib, didExitRegion region: CLRegion) {
    //User is left a region
}

Using iBeacons

This technology will require the device to have Bluetooth Service ON. If enabled your app will monitor any BTLE device in the vicinity. By default this is automatically done by our library so there is not really any additionally step to take.

However you might want to retrieve the proximity level of any beacons around you. This is only possible while the app is in foreground. To get this information you will need to implement the following delegate:

- (void)notificarePushLib:(NotificarePushLib *)library didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
    //Handle list of beacons in the proximity
    //Do not call any UI thread from here
}
func notificarePushLib(_ library: NotificarePushLib, didRangeBeacons beacons: [Any], in region: CLBeaconRegion) {
    //Handle list of beacons in the proximity
    //Do not call any UI thread from here
}

If by any reason your app fails to start ranging beacons, it will trigger the following delegate:

- (void)notificarePushLib:(NotificarePushLib *)library rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error{
    //Handle error
}
func notificarePushLib(_ library: NotificarePushLib, rangingBeaconsDidFailFor region: CLBeaconRegion, withError error: Error?) {
    //Handle error
}