How to notify user when iBeacon range is "Immediate" or "near"? - ios

Users will only get notified when they are close enough to the beacon, since then didEnterRegion dose not work properly.
My code is like this:
if ([region isKindOfClass:[CLBeaconRegion class]] && ([beaconRegionInStringFormat isEqualToString:#"Immediate"] || [beaconRegionInStringFormat isEqualToString:#"Near"]))
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Please open the application";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
But the notification will keep sending to users. How can I only get notified once?

1. Adding a flag to your controller
Interface:
#property (nonatomic) BOOL userNotified;
Implementation:
if (!self.userNotified && [region isKindOfClass:[CLBeaconRegion class]] && ([beaconRegionInStringFormat isEqualToString:#"Immediate"] || [beaconRegionInStringFormat isEqualToString:#"Near"]))
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Please open the application";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.userNotified = YES;
}
2. Using the GCD (Grand Central Dispatch)
Using this method the code will be executed only once per app launch.
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
if ([region isKindOfClass:[CLBeaconRegion class]] && ([beaconRegionInStringFormat isEqualToString:#"Immediate"] || [beaconRegionInStringFormat isEqualToString:#"Near"]))
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Please open the application";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
});

Related

How to get local notification display on active state exactly as it shows up in inactive sate

I am currently doing this, but the notification repeats several times.Please help.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
//localNotification.userInfo = #"Hey";
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = self.notiname;
localNotification.fireDate = [NSDate date];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
AudioServicesPlaySystemSound(1104);
}
}

UILocalNotification doesn't fire in didEnterRegion

I have implemented the
didEnterRegion
method and it works in background for example if I show an alertview...even with the app in background (when I foreground the app the alertViews show)
I use alertview only to test the didEnterRegion method in background and it works...but now im trying to fire an UILocalNotification in didEnterRegion but the UILocalNotification is not firing. Theres my code:
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
int iRegiao = [region.identifier intValue];
Location *ocorrencia = (Location *)[self.locations.objects objectAtIndex:iRegiao];
// NSLog(#"Voce está proximo da %#", ocorrencia.name);
// UIApplication *app = [UIApplication sharedApplication];
UILocalNotification *notification = [[UILocalNotification alloc] init];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
notification.fireDate = [NSDate date];// Now here you can manage the fire time.
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = ocorrencia.name;
notification.alertAction = ocorrencia.name;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
Are you targeting iOS 8? If so, you need to ask for permission for local notifications.
Try this:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge categories:nil]];
}
The respondsToSelector: check is needed if you are also supporting iOS 7 or below.
Did you try to use - (void)presentLocalNotificationNow:(UILocalNotification *)notification on UIApplication? (it ignores fireDate)

How to display notifications when multiple iBeacons are in range

I have 3 iBeacons which are placed in 3 different rooms. When I walk into each of rooms I'd like to receive a notification while my app is closed that tells me which room I'm in.
My beacons all have the UUID but different major and minor versions.
This is what we've implemented so far in our class (not in App Delegate)
-(void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region {
// firstBeacon is the closest beacon
CLBeacon *firstBeacon = [beacons firstObject];
NSLog(#" Major %# Minor %#", firstBeacon.major, firstBeacon.minor);
int major = [firstBeacon.major intValue];
int minor = [firstBeacon.minor intValue];
if (major == 43005 && minor == 52679) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.beaconColour.text = #"Green";
}
else if (major == 48891 && minor == 47852) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Light Blue";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.beaconColour.text = #"Light Blue";
}
else if (major == 59510 && minor == 42953) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Dark Blue";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.beaconColour.text = #"Dark Blue";
}
self.major.text = [NSString stringWithFormat:#"%d", major];
self.minor.text = [NSString stringWithFormat:#"%d", minor];
}
Updated code based on answer
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:#"com.accenture.testregion"];
self.myBeaconRegion.notifyEntryStateOnDisplay = YES;
self.myBeaconRegion.notifyOnEntry = YES;
self.myBeaconRegion.notifyOnExit = YES;
[self.locationManager startMonitoringForRegion:self.myBeaconRegion];
}
- (void)didReceiveMemoryWarnins {
[super didReceiveMemoryWarning];
}
BOOL _isInsideRegion;
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"didEnterRegion");
if ([region isKindOfClass:[CLBeaconRegion class]]) {
CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
int major = [beaconRegion.major intValue];
int minor = [beaconRegion.minor intValue];
NSLog(#" Major %d Minor %d", major, minor);
if (major == 43005 && minor == 52679) {
self.beaconColour.text = #"Green";
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
_isInsideRegion = YES;
}
else if (major == 48891 && minor == 47852) {
self.beaconColour.text = #"Light Blue";
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
_isInsideRegion = YES;
}
else if (major == 59510 && minor == 42953) {
self.beaconColour.text = #"Dark Blue";
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
_isInsideRegion = YES;
}
}
}
Try not to get first object from beacons array, you should enumerate it and compare which one is which, sometimes you can receive a signal from few beacons.
I made it work by calling didEnterRegion: delegate instead on didRangeBeacons:
You should also create a boolean flag (variable) to prevent duplicate sending of notification. And mark it true inside your if condition when minor/major match and set it to false in didExitRegion:
BOOL _isInsideRegion;
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
int major = [beaconRegion.major intValue];
int minor = [beaconRegion.major.minor intValue];
if (major == 43005 && minor == 52679) {
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
_isInsideRegion = YES;
self.beaconColour.text = #"Green";
}
else if (major == 48891 && minor == 47852) {
if (!_isInsideRegion) {....
}
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
if (major == 43005 && minor == 52679) {
if (!_isInsideRegion) {
// You can send another notification to inform user that he left the region
}
_isInsideRegion = NO;
}
When your app is in the background, you don't get region entry/exit events super quickly. It can take up to 15 minutes to get a notification. See here: http://developer.radiusnetworks.com/2013/11/13/ibeacon-monitoring-in-the-background-and-foreground.html

Geofencing when App is killed by user in iOS7.1

In iOS7.1 , when a user kills an app , does the geofencing still works?
If geofencing is detecting the device is entering or exiting the region, can it trigger a local notification (even when the user has killed the app ) ?
you GeoFencing still works it works like push notification / or passbook same thing it will still generate notification for your app. bellow function will fire even if app is not running in background.
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSString *event = [NSString stringWithFormat:#"didExitRegion %# at %#", region.identifier, [NSDate date]];
[self updateWithEvent:event];
//implement local notification:
UIApplication *app = [UIApplication sharedApplication];
UILocalNotification *notification = [[UILocalNotification alloc] init];
[[UIApplication sharedApplication] cancelAllLocalNotifications];
if (notification == nil)
return;
notification.alertBody = [NSString stringWithFormat:#"Did You Lock Your House?"];
notification.alertAction = #"Lock House";
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
[app presentLocalNotificationNow:notification];
[notification release];
}

Is NSNotificationCenter necessary to cancel UILocalnotficiation?

I want to cancel a UILocalnotification , when i cancel notification still the notification is being fired . I wanted to know do i have to call any delegate method in appdelegate to cancel notification .the code which i am using is executing correctly .but the notification is getting fired .
Should i use NSNotification center which has removeObserver method to cancel uilocalnotification.
Does UILocalnotification fires notification from the app or from the device.
UPDATE - This is how i am scheduling my notification
-(UILocalNotification *)scheduleNotification :(int)remedyID
{
NSString *descriptionBody;
NSInteger frequency;
UILocalNotification *notif = [[UILocalNotification alloc] init];
NSLog(#"%d",remedyID);
descriptionBody =[[self remedyDetailsForRemedyID:remedyID] objectForKey:#"RemedyTxtDic"];
frequency = [[[self remedyDetailsForRemedyID:remedyID] objectForKey:#"RemedyFrequency"]intValue];
NSArray *notificationFireDates = [self fireDatesForFrequency:frequency];
for (NSDate *fireDate in notificationFireDates)
{
notif.timeZone = [NSTimeZone defaultTimeZone];
notif.repeatInterval = NSDayCalendarUnit;
notif.alertBody = [NSString stringWithString:descriptionBody];
notif.alertAction = #"Show me";
notif.soundName = UILocalNotificationDefaultSoundName;
notif.applicationIconBadgeNumber = 1;
notif.fireDate = fireDate;
NSDictionary *userDict = [NSDictionary dictionaryWithObjectsAndKeys:notif.alertBody, #"kRemindMeNotificationDataKey", [NSNumber numberWithInt:remedyID],kRemindMeNotificationRemedyIDKey,
nil];
notif.userInfo = userDict;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
}
return notif;
}
Cancelling notification
- (void)cancelNotification:(int)remedyId
{
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
NSLog(#"Cancelling... Before %d",[[[UIApplication sharedApplication]scheduledLocalNotifications]count]);
for (UILocalNotification *notification in notifications)
{
int notifRemedyId = [[notification.userInfo objectForKey:#"kRemindMeNotificationRemedyIDKey"]intValue];
NSLog(#"remedyID : %d",remedyId);
NSLog(#"notifyId : %d",notifRemedyId);
if (remedyId == notifRemedyId) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
NSLog(#"Cancelling... After %d",[[[UIApplication sharedApplication]scheduledLocalNotifications]count]);
}
NSNotification center which has removeObserver method to cancel uilocalnotification.
NSNotificationCenter has nothing to do with UILocalNotification. I'm sorry that they both use "notification" somewhere in their names, but that is just coincidence really.
scheduledLocalNotifications will give you the list of all scheduled notifications and use
- (void)cancelLocalNotification:(UILocalNotification *)notification
or you can cancel them all using:
[[UIApplication sharedApplication] cancelAllLocalNotifications];
Edit :
NSString *notifRemedyId = #"notifRemedyId";
UILocalNotification *localnotif=[[UILocalNotification alloc]init];
NSDictionary *userDict = [NSDictionary dictionaryWithObjectsAndKeys:#"kRemindMeNotificationRemedyIDKey", kRemindMeNotificationRemedyIDKey,YOUR_REMEDYID,#"notifRemedyId",nil];
localnotif.userInfo = userDict;
[[UIApplication sharedApplication] scheduleLocalNotification:localnotif];
Cancel as :
for (UILocalNotification *aNotif in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
if ([[aNotif.userInfo objectForKey: kRemindMeNotificationRemedyIDKey] isEqualToString:#"kRemindMeNotificationRemedyIDKey"]) {
if (remedyId == [[aNotif.userInfo objectForKey: kRemindMeNotificationRemedyIDKey] intValue]) {
[[UIApplication sharedApplication] cancelLocalNotification:aNotif];
break;
}
}
}
Hope it helps you.

Resources