Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove fired Location-Based notification when user exits region

I've setup (default iOS8) location-based notifications for my app.

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.regionTriggersOnce = NO;
notification.userInfo = @{ @"notification_id" : @"someID" };
notification.region = region;
notification.alertBody = alertBody;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];

When a user enters the specified region, the notification is shown in the NotificationCenter correctly.

However, I want to remove that notification message when the user exits that region, because it makes little sense for the user to go home and look at the notification center until they recieve a message which looks like so:

"You are at XXXXX!"

Has anyone tried something similar? The documentation is unclear on how this can be done.

like image 566
Vrasidas Avatar asked Jul 27 '15 07:07

Vrasidas


2 Answers

CLRegion object has special properties for that: notifyOnEntry and notifyOnExit.
Everything that you need is update code in this way:

CLRegion *region = .... // Configure region here
region.notifyOnEntry = YES;
region.notifyOnExit = NO;  

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.regionTriggersOnce = NO;
notification.userInfo = @{ @"notification_id" : @"someID" };
notification.region = region;
notification.alertBody = alertBody;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];

Here is Apple documentation that explains it:

@property(nonatomic, copy) CLRegion *region
Assigning a value to this property causes the local notification to be delivered when the user crosses the region’s boundary.
The region object itself defines whether the notification is triggered when the user enters or exits the region.

like image 109
Vlad Papko Avatar answered Oct 04 '22 17:10

Vlad Papko


I was really tired yesterday and couldn't complete my answer in time.

Based on some answers here I have only a clue what you have to do. I did not tried it myself (geofencing is a really a pain to test, I know that because I'm working on a geofencing project atm.), I also never had to delete a delivered notification from the Notification Center before.

I assume your application will not terminate due the whole process. So we won't use startMonitoringForRegion function here.

Answer written in Swift 2.0 (It's not that hard to translate it to ObjC).

func createAndRegisterSomeNotificationSomewhere() {

    let region = CLCircularRegion(center: someCoordinates, radius: someRadius, identifier: someIdentifier)

    region.notifyOnEntry = true
    region.notifyOnExit = true

    let locationNotification = UILocalNotification()
    locationNotification.alertBody = "someAlertBody"
    locationNotification.userInfo = ["notification_id" : "someID"]
    locationNotification.regionTriggersOnce = false
    locationNotification.region = region // remember 'presentLocalNotificationNow' will not work if this value is set

    UIApplication.sharedApplication().scheduleLocalNotification(locationNotification)
}

/* CLLocationManagerDelegate provides two function */

// func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion)
// func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion)

/* If I'm not mistaken they are only called for monitored regions and not location based local notifications */
/* I mean you will have to use something like: self.locationManager.startMonitoringForRegion(someCircularRegion) */
/* Correct me if I'm wrong. So consider to rebuild the following logic to ease everything if you want to monitor regions. */

/* Now when you receive your location notification */
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {

    if let region = notification.region {

        self.locationManager.requestStateForRegion(region)

        /* based on other answers this will remove your noticaiton from NC and cancel from showing it anywhere */
        application.cancelLocalNotification(notification)
        /* but we need this notification still be scheduled because 'region.notifyOnExit = true' should fire it again later */
        application.scheduleLocalNotification(notification)
    }
}

func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) {

    /* this is not the best solution, because it adds some latency to the dilivery code and CLRegionState can also be Unknown sometimes */
    /* I'd go with the two functions above if I only had up to 20 regions to monitor (max region limit per App, read CLLocationManager docs) */
    /* the mechanics would be more clear and save */

    switch state {

    case .Inside:

        /* create a new noticiation with the same cpecs as the cancled notification but this time withot the region */
        let sameNotificationAsAbove = UILocalNotification()
        /* if you really need to know your IDs inside userInfo so create some good mechanics to pass these before canceling */
        /* at least I would save the identifier of the region iside the noticiation */
        /* save the notification somewhere to delete it later from NC */
        self.someArrayToSaveDeliveredNotifications.append(sameNotificationAsAbove)

        /* fire the notification */
        UIApplication.sharedApplication().presentLocalNotificationNow(sameNotificationAsAbove)

    case default:

        /* if it is true that notication inside NC can be deleted just by calling 'cancelLocalNotification' function */
        /* so find your notification inside someArrayToSaveDeliveredNotifications bases on the region.identier which you saved inside userInfo */
        let notificationToCancel = self.getNotificationForIdentifier(region.identifier)

        UIApplication.sharedApplication().cancelLocalNotification(notificationToCancel)
        /* this should delete your notification from NC based on other answers */
    }
}

This is some kind of pseudo mechanics I would build if I had to, so if anything is wrong or not correct I would appreciate to hear your feedback. :)

like image 22
DevAndArtist Avatar answered Oct 04 '22 17:10

DevAndArtist