What I am trying to achieve is described in the following steps
1.User opens the app, navigates blah blah blah
2.User presses the home button, the app shuts itself
3.A background task for detecting CLbeacons starts. On every detection, A UILocalNotification is fired immediately, so as to make the user aware that a beacon has been discovered.
Now what happens with me
I open the app, navigate then press the home button to shut the app
The phone slowly darkens itself, i.e it goes to the slide to unlock state. Here no notification gets fired; Hell, the CLLocationManger's method -(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region doesn't get called at all.
The phone goes to sleep. I slide open the phone to awake it; Immediately multiple `UIlocalNotifications enter.
Can anyone explain to me why is this happening?
//
// AppDelegate.m
// Beacon Proximity
//
// Created by Debanjan Chakraborty on 7/15/14.
// Copyright (c) 2014 Debanjan Chakraborty. All rights reserved.
//
#import "AppDelegate.h"
#import "CustomerRegViewController.h"
#import "IntialViewController.h"
#import "BeaconProduct.h"
#import "DBManager.h"
#import "APLDefaults.h"
#import "ScanViewController.h"
typedef NS_ENUM(NSUInteger, BeaconType)
{
Check,
Bundle
};
#interface AppDelegate ()<CLLocationManagerDelegate>
#property CLLocationManager *locationAppManager;
#property (nonatomic) NSInteger localNotificationCount;
//#property (nonatomic,strong) UILocalNotification *localNotification;
//#property (nonatomic) NSTimer *timerForNotifier;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
// app already launched
}
else
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self entryDatabase];
}
[[UIApplication sharedApplication] cancelAllLocalNotifications];
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification)
{
NSLog(#" aache ?");
// self.localNotificationCount = 0;
UIAlertView *aw = [[UIAlertView alloc] initWithTitle:#"Case 1" message: notification.alertBody delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[aw show];
}
application.applicationIconBadgeNumber = 0;
return YES;
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#"<>"]];
token = [token stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"content---%#", token);
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"Error %#",err.localizedDescription);
}
- (void)applicationWillResignActive:(UIApplication *)application
{
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"])
{
NSLog(#" Will REsign and initialise");
}
else
{
NSLog(#" Will REsign?");
}
}
-(void)applicationWillTerminate:(UIApplication *)application
{
NSLog(#" terminated");
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
[self initialise];
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
application.applicationIconBadgeNumber=0;
for (NSUUID *uuid in [APLDefaults sharedDefaults].supportedProximityUUIDs)
{
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:[uuid UUIDString]];
[self.locationAppManager stopMonitoringForRegion:region];
}
self.locationAppManager = nil;
}
-(void)insert:(NSDate *)fire WithBeaconType:(BeaconType )beaconType ForBeacon:(CLBeacon *)beacon
{
self.localNotificationCount++;
UILocalNotification *localNotification = [UILocalNotification new];
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber =self.localNotificationCount;
localNotification.fireDate = [NSDate date];
localNotification.alertAction = #"Show me";
if(beaconType == Check)
{
localNotification.alertBody = [NSString stringWithFormat:#"Check out new offers"];
localNotification.alertAction = NSLocalizedString(#"Read Offer", nil);
}
else
{
localNotification.alertBody = [NSString stringWithFormat:#"You've reached offers. Grab them before they expire soon"];
localNotification.alertAction = NSLocalizedString(#"Grab Offer", nil);
}
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
NSLog(#" should Notify minor is %d and major is %d",[beacon.minor integerValue],[beacon.major integerValue]);
[[DBManager getSharedInstance] updateNotifiedTimeForBeacon:beacon];
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
self.localNotificationCount = 0;
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
-(UIViewController *)omegaScreen
{
UIStoryboard *strybrd = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
NSString *viewId=[[NSUserDefaults standardUserDefaults]objectForKey:#"custId"]?#"initial":#"custReg";
UIViewController *controller=[strybrd instantiateViewControllerWithIdentifier:viewId];
if([[NSUserDefaults standardUserDefaults] objectForKey:#"custId"])
[self initialise];
return [viewId isEqualToString:#"initial"]?(IntialViewController *)controller:(CustomerRegViewController *)controller;
}
-(void)initialise
{
self.locationAppManager = [[CLLocationManager alloc] init];
self.locationAppManager.delegate = self;
for (NSUUID *uuid in [APLDefaults sharedDefaults].supportedProximityUUIDs)
{
NSLog(#" uuid is %#",uuid.UUIDString);
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:[uuid UUIDString]];
region.notifyEntryStateOnDisplay=YES;
[self.locationAppManager startMonitoringForRegion:region];
}
self.localNotificationCount = -1;
}
- (void) locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
NSLog(#" it did");
if([region isKindOfClass:[CLBeaconRegion class]])
{
[self.locationAppManager requestStateForRegion:(CLBeaconRegion*)region];
}
}
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
if (state == CLRegionStateInside)
{
//Start Ranging
[manager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
}
}
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region
{
if ([region isKindOfClass:[CLBeaconRegion class]])
{
[self.locationAppManager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
}
}
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
// if([self runningInBackground])
// {
// NSLog(#" didRangeBeacons in App Delegate");
for (CLBeacon *beacon in beacons)
{
if([[DBManager getSharedInstance]shouldNotifyFor:beacon])
{
BeaconType type;
if([beacon.major integerValue]==0)
{
type = Check;
}
else
{
type = Bundle;
}
[self insert:[NSDate date]WithBeaconType:type ForBeacon:beacon];
}
}
// }
}
-(BOOL) runningInBackground
{
UIApplicationState state = [UIApplication sharedApplication].applicationState;
BOOL result = (state == UIApplicationStateBackground);
return result;
}
-(void)resetStatus
{
NSLog(#" timer has been fired");
}
-(void)entryDatabase
{
NSMutableArray *localArray = [NSMutableArray new];
BeaconProduct *bP1 = [[BeaconProduct alloc] initWithProductSku:#"1" andId:#"1" andbTitle:#"BeaconAdTitle1" andDescription:#"Description1" andCurrency:#"Rupees" andSmallImage:#"Shampoo" andLargeImage:#"Shampoo" andPrice:[NSNumber numberWithInteger:700]];
BeaconProduct *bP2 = [[BeaconProduct alloc] initWithProductSku:#"2" andId:#"1" andbTitle:#"BeaconAdTitle2" andDescription:#"Description2" andCurrency:#"Rupees" andSmallImage:#"conditionerFree" andLargeImage:#"conditionerFree" andPrice:[NSNumber numberWithInteger:200]];
BeaconProduct *bP3 = [[BeaconProduct alloc] initWithProductSku:#"3" andId:#"2" andbTitle:#"BeaconAdTitle3" andDescription:#"Description3" andCurrency:#"Rupees" andSmallImage:#"soap" andLargeImage:#"soap" andPrice:[NSNumber numberWithFloat:20.50]];
BeaconProduct *bP4 = [[BeaconProduct alloc] initWithProductSku:#"4" andId:#"3" andbTitle:#"BeaconAdTitle4" andDescription:#"Description4" andCurrency:#"Rupees" andSmallImage:#"shirt" andLargeImage:#"shirt" andPrice:[NSNumber numberWithFloat:250]];
[localArray addObject:bP1];
[localArray addObject:bP2];
[localArray addObject:bP3];
[localArray addObject:bP4];
[[DBManager getSharedInstance] insertBeaconProduct:localArray];
}
#end
You should post your code so we can explain this definitively, but it sounds like you simply have region.notifyEntryStateOnDisplay = YES; when setting up your region. When you have that option set, you will get an extra callback to your region entry callback from CLLocationManager every time you illuminate the display.
EDIT: After seeing the code, I also noticed that the app starts monitoring when it is about to to the background, then stops it when it goes back into the foreground. I suspect this may be complicating the issue and giving you extra callbacks causing extra notifications. It doesn't look like there is any reason to keep stopping and restarting monitoring. I would suggest you simply set up monitoring of your beacon regions when the app starts up, and leave monitoring going. This combined with setting region.notifyEntryStateOnDisplay=NO should prevent the multiple notifications.
SECOND EDIT: As to point (2), you should understand that you generally CANNOT range in the background at all. Once your app leaves the foreground, you can only get callbacks to didRangeBeacons: inRegion: for about five seconds, at which time such callbacks stop until the app is woken up again. One way you can wake it up is by transitioning from being in/out of a beacon region using the monitoring APIs. However, you should understand that in the background, these transitions are not always instantaneous and can take up to 15 minutes. See here for details.
Related
I have created multiple geo-fence to monitor region entry/exit events.
I have created a location manager in AppDelegate.h file.
#interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property(nonatomic,retain)CLLocationManager *locationManager;
#property(nonatomic,retain)CLLocation *currentLocation;
+(AppDelegate *)sharedDelegate;
AppDelegate.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification) {
NSLog(#"AppDelegate didFinishLaunchingWithOptions");
application.applicationIconBadgeNumber = 0;
}
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)])
{
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:settings];
}
else // iOS 7 or earlier
{
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:myTypes];
}
if (!self.locationManager)
{
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
//locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locationManager.distanceFilter = 2.0f;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[self.locationManager requestAlwaysAuthorization];
}
if ([self.locationManager respondsToSelector:#selector(allowsBackgroundLocationUpdates)])
{
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
if ([self.locationManager respondsToSelector:#selector(pausesLocationUpdatesAutomatically)])
{
self.locationManager.pausesLocationUpdatesAutomatically= NO;
}
[self.locationManager stopMonitoringSignificantLocationChanges];
if ([CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] != kCLAuthorizationStatusDenied)
{
[self.locationManager startUpdatingLocation];
}
// Override point for customization after application launch.
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
NSLog(#"Started monitoring %# region",region.identifier);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
NSLog(#"%#",[locations description]);
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication] applicationState]==UIApplicationStateInactive)
{
UILocalNotification *localnotification = [[UILocalNotification alloc]init];
localnotification.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
localnotification.alertBody=#"You are enter in region.";
localnotification.timeZone=[NSTimeZone defaultTimeZone];
localnotification.repeatInterval = 0;
localnotification.hasAction=YES;
[[UIApplication sharedApplication]scheduleLocalNotification:localnotification];
}
else
{
[[[UIAlertView alloc]initWithTitle:#"message" message:#"Enter into region." delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok ", nil] show];
}
});
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication] applicationState]==UIApplicationStateInactive)
{
UILocalNotification *localnotificationExit = [[UILocalNotification alloc]init];
localnotificationExit.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
localnotificationExit.alertBody=#"You are exit from region.";
NSLog(#"Exit from region.");
localnotificationExit.timeZone=[NSTimeZone defaultTimeZone];
localnotificationExit.repeatInterval = 0;
localnotificationExit.hasAction=YES;
[[UIApplication sharedApplication]scheduleLocalNotification:localnotificationExit];
}
else
{
[[[UIAlertView alloc]initWithTitle:#"message" message:#"Exit from region." delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok ", nil] show];
}
});
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
[[[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
This things are to manage the region monitoring.
Now my view controller are adding the regions for monitoring.
-(void)AddRegionsInGeoFence
{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
//----1
CLLocationCoordinate2D centerCoordinate1 = CLLocationCoordinate2DMake(23.046518, 72.543337);
CLCircularRegion *region1 =[[CLCircularRegion alloc] initWithCenter:centerCoordinate1 radius:200 identifier:#"Location First"];
NSLog(#"%#",[region1 description]);
region1.notifyOnEntry=YES;
region1.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region1];
NSLog(#"Started Monitoring- %#", [region1 description]);
}
[self.mapview setShowsUserLocation:YES];
[self.mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
//----2
CLLocationCoordinate2D centercoordinate2=CLLocationCoordinate2DMake(23.064381, 72.531181);
CLCircularRegion *region2=[[CLCircularRegion alloc]initWithCenter:centercoordinate2 radius:200 identifier:#"Location Second"];
NSLog(#"%#",[region2 description]);
region2.notifyOnEntry=YES;
region2.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region2];
NSLog(#"Started Monitoring- %#", [region2 description]);
}
//----3
CLLocationCoordinate2D centercoordinate3=CLLocationCoordinate2DMake(23.083583,72.546441);
CLCircularRegion *region3=[[CLCircularRegion alloc]initWithCenter:centercoordinate3 radius:200 identifier:#"Location Third"];
NSLog(#"%#",[region3 description]);
region3.notifyOnEntry=YES;
region3.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region3];
NSLog(#"Started Monitoring- %#", [region3 description]);
}
//4
CLLocationCoordinate2D centercoordinate4=CLLocationCoordinate2DMake(23.122255, 72.584499);
CLCircularRegion *region4=[[CLCircularRegion alloc]initWithCenter:centercoordinate4 radius:500 identifier:#"Location Fourth"];
NSLog(#"%#",[region4 description]);
region4.notifyOnEntry=YES;
region4.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region4];
NSLog(#"Started Monitoring- %#", [region4 description]);
[standardDefaults setBool:YES forKey:#"EnterRegion"];
[standardDefaults synchronize];
}
}
My Problem is region monitoring methods are called multiple times even if I am not moving in side the region itself. Everything else is working fine, Accuracy buffer is around 50-80 meters that is fine for me.
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
Also if I am turning off Wi-Fi then it's calling up these methods back to back saying exit from region and enter in to region. As far as I know GPS accuracy is depends on Wi-Fi.
Any help would be highly appreciated.
a Possible workaround in the interim while the apple bug gets fixed is to rate limit the callback; thereby not acting on all the callbacks but limiting the rate at which the callbacks can get processed.
Callback execution portions that happen before the time period expires get ignored.
Here is and example code that could assist, not tested:
The rate is limited to 2 seconds.
-(void)methodRateLimit {
#synchronized(self) {
// rate limit begin
static NSDate *lastTimeExit = nil;
if (!lastTimeExit) {
lastTimeExit = [NSDate distantPast]; // way back in time
}
NSDate *now = [NSDate date];
if ([now timeIntervalSinceDate:lastTimeExit] > 2) {
// do work here
NSLog(#"Executing");
lastTimeExit = now;
} else {
NSLog(#"Limiting");
}
}
}
I'm implementing local notifications,there are 3 notifications to be send at different times of a day.
in my app delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
}
and in DidReceiveLocalNotifications
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSString *checkbtn= [[NSUserDefaults standardUserDefaults]valueForKey:#"on"];
if([checkbtn isEqualToString:#"SwitchOn"])
{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Green Actions"
message:notification.alertBody
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
//}
}
if i remove this alert view,i m not getting any notification in foreground but if i use this then i m getting notification alert every second.
this is my viewcontroller code
- (void)viewDidLoad {
[super viewDidLoad];
appdelegate= (AppDelegate *) [[UIApplication sharedApplication]delegate];
[self createCustomeNavigationBar];
self.navigationController.navigationBar.translucent = NO;
//[self notificationOne];
[self.switchbutton addTarget:self action:#selector(switchToggled:) forControlEvents:UIControlEventValueChanged];
[self.switchbutton1 addTarget:self action:#selector(switchToggled1:) forControlEvents:UIControlEventValueChanged];
[self.switchbutton3 addTarget:self action:#selector(switchToggled3:) forControlEvents:UIControlEventValueChanged];
if ([[NSUserDefaults standardUserDefaults]valueForKey:#"on"])
{
UILocalNotification* n1 = [[UILocalNotification alloc] init];
n1.fireDate = [NSDate dateWithTimeIntervalSinceNow: 160];
n1.alertBody = #"one";
[[UIApplication sharedApplication] scheduleLocalNotification: n1];
}
if ([[NSUserDefaults standardUserDefaults]valueForKey:#"SwitchOneon"])
{
UILocalNotification* n2 = [[UILocalNotification alloc] init];
n2.fireDate = [NSDate dateWithTimeIntervalSinceNow: 190];
n2.alertBody = #"two";
[[UIApplication sharedApplication] scheduleLocalNotification: n2];
}
// Do any additional setup after loading the view from its nib.
}
- (void) switchToggled:(id)sender {
self.switchbutton = (UISwitch *)sender;
if ([self.switchbutton isOn]) {
NSLog(#"its on!");
[[NSUserDefaults standardUserDefaults]setObject:#"SwitchOn" forKey:#"on"];
[[NSUserDefaults standardUserDefaults]synchronize];
} else {
[[NSUserDefaults standardUserDefaults]removeObjectForKey:#"on"];
NSLog(#"its off!");
}
}
- (void) switchToggled1:(id)sender {
self.switchbutton1 = (UISwitch *)sender;
if ([self.switchbutton1 isOn]) {
NSLog(#"its on!");
[[NSUserDefaults standardUserDefaults]setObject:#"SwitchOn" forKey:#"SwitchOneon"];
[[NSUserDefaults standardUserDefaults]synchronize];
} else {
[[NSUserDefaults standardUserDefaults]removeObjectForKey:#"SwitchOneon"];
NSLog(#"its off!");
}
}
- (void) switchToggled3:(id)sender {
self.switchbutton3 = (UISwitch *)sender;
if ([self.switchbutton3 isOn]) {
NSLog(#"its on!");
[[NSUserDefaults standardUserDefaults]setObject:#"SwitchOn" forKey:#"SwitchThreeon"];
[[NSUserDefaults standardUserDefaults]synchronize];
} else {
[[NSUserDefaults standardUserDefaults]removeObjectForKey:#"SwitchThreeon"];
NSLog(#"its off!");
}
}
and also i m getting some different text in alert view which i used earlier just for testing purpose,even after changing it,i m getting the same old previous text.
I am sure that problem isn't with alert code. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification, you're getting notification. But when your app is in foreground (or active) you should handle it manually. In your case, you're handling it with UIAlertView so it will be visible in alert, but once you removed, you're not able to see a notification when your app was in foreground (or active) state.
I built a simple ios app with IBeacon, when the app is in foreground or background it works ok but after rebooting my phone, my app stops getting CoreLocation delegate callbacks. This is my AppDelegate.m code.
#import "AppDelegate.h"
#import <CoreLocation/CoreLocation.h>
#import "ViewController.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound
categories:nil]];
}
if(launchOptions != nil){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alerta"
message:[launchOptions[UIApplicationLaunchOptionsLocalNotificationKey] description]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:#"B39ED98FF-2900-441A-802F-9C398FC199D2"];
NSString *regionIdentifier = #"iBeacons region 1";
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID: beaconUUID identifier: regionIdentifier ];
beaconRegion.notifyEntryStateOnDisplay = YES;
self.locationManager = [[CLLocationManager alloc]init];
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]){
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
//self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startMonitoringForRegion:beaconRegion];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
[self.locationManager startUpdatingLocation];
return YES;
}
-(void)sendLocalNotificationWithMessage:(NSString*)message {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = message;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
- (void) locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
ViewController *viewController = (ViewController*) self.window.rootViewController;
viewController.beacons = beacons;
[viewController.tableView reloadData];
NSString *message = #"";
if(beacons.count > 0){
CLBeacon *nearestBeacon = beacons.firstObject;
if(nearestBeacon.proximity == self.lastProximity || nearestBeacon.proximity == CLProximityUnknown){
return;
}
self.lastProximity = nearestBeacon.proximity;
switch (nearestBeacon.proximity) {
case CLProximityFar:
message = #"CLProximityFar";
break;
case CLProximityNear:
message= #"CLProximityNear";
break;
case CLProximityImmediate:
message= #"CLProximityImmediate";
break;
case CLProximityUnknown:
return;
}
}else {
message = #"No BEACONS";
}
NSLog(#"%#", message);
[self sendLocalNotificationWithMessage:message];
}
- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
[manager startRangingBeaconsInRegion:(CLBeaconRegion*) region];
[self.locationManager startUpdatingLocation];
NSLog(#"INSIDE REGION");
[self sendLocalNotificationWithMessage:#"INSIDE REGION"];
}
- (void) locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*) region];
[self.locationManager stopUpdatingLocation];
NSLog(#"OUTSIDE REGION");
[self sendLocalNotificationWithMessage:#"OUTSIDE REGION"];
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
if (state == CLRegionStateInside) {
//Start Ranging
[manager startRangingBeaconsInRegion:(CLBeaconRegion*) region];
[self.locationManager startUpdatingLocation];
NSLog(#"INSIDE REGION");
[self sendLocalNotificationWithMessage:#"INSIDE REGION"];
}
else{
//Stop Ranging
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*) region];
[self.locationManager stopUpdatingLocation];
NSLog(#"OUTSIDE REGION");
[self sendLocalNotificationWithMessage:#"OUTSIDE REGION"];
}
}
-(void)application:(UIApplication *)application didReceiveLocalNotification:(NSDictionary *)userInfo {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"ALERT"
message:#"didReceiveLocalNotification"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
I cant find what is the issue, i need your help!
The code looks OK. When testing this, I would recommend you do the following:
Launch your app
Turn on your beacon
Verify you get a didEnterRegion callback.
Turn off your beacon
Verify you get a didExitRegion callback.
Reboot your phone
Wait at least 2 minutes (it takes a bit of time before CoreLocation fully starts up after reboot.)
Turn on your beacon
Wait a few minutes to see if you get a didEnterRegion callback.
In my app I want to fetch and upload location on server in regular intervals. for foreground it works fine but for background it has issue as described below. One thing to mention here I use different class for foreground and separate code for background.
To fetch location in background I do the following. It does upload location for about 24 - 40 hours but get stopped after 24-40 hours. I did not get "willTerminate" event. I have also written code to capture global execption so that I could log SigKill if user kill my app but it too does not get logged reason could be we can't catch SigKill.
Now I am stuck don't know what to do to keep my app alive in background to upload location in regular intervals.
//////////////////////////////// didfinish lauch ///////////////////////////////
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
return YES;
}
////////// **did enter background**
- (void) applicationDidEnterBackground:(UIApplication *)application
{
self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
timer = [[NSTimer scheduledTimerWithTimeInterval:8*60
target:self
selector:#selector(changeAccuracy)
userInfo:nil
repeats:YES] retain];
[self.locationManager startUpdatingLocation];
}
- (void) changeAccuracy
{
self.bCallbackStarted = NO;
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:100];
}
///////// **did enter fore ground**
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self.locationManager stopUpdatingLocation];
}
////////// **did update location**
-(void)locationManager:(CLLocationManager *)lm didUpdateLocations:(NSArray *)locations
{
if (self.bCallbackStarted == YES) {
NSString* logStr = [NSString stringWithFormat:#"URLFilteringAppDelegate::didUpdateLocations not uploading location because self.bCallbackStarted == YES"];
LOGI(logStr)
return;
}
self.bCallbackStarted = YES;
[[AppUtility sharedInstance] setLocationStatus:YES];
CLLocation *location = [locations lastObject];
if(location.coordinate.latitude == 0 && location.coordinate.longitude == 0)
{
[UserSettings sharedInstance].Latitude = [NSString stringWithFormat:#"%#", #"Unavailable"];
[UserSettings sharedInstance].Longitude = [NSString stringWithFormat:#"%#", #"Unavailable"];
}
else
{
[UserSettings sharedInstance].Latitude = [NSString stringWithFormat:#"%.8f", location.coordinate.latitude];
[UserSettings sharedInstance].Longitude = [NSString stringWithFormat:#"%.8f", location.coordinate.longitude];
}
[[LocationManager sharedInstance] sendLocation];
/// this is set to save battery
[lm setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[lm setDistanceFilter:99999];
}
I have this code which send user notifications every time the distance between an event that occur in a local JSON file and his current location is < 100 meter asking him whether he is at that event or not , when he presses on yes then that event will be marked as attended. the thing is I tried to do that by using some code i found online but I'm not sure if it is the right way to do it, anyway i tested it on my iPhone and what happened is when i arrived to an event location it kept sending unstoppable notifications and when i try to press yes or no nothing actually happen it keeps sending these notifications. Can anyone plz explain for me what is going wrong, I'm not very familiar with Xcode and objective-C language. The code i used is shown below.
in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// load Core Data
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
NSLog(#"No NSManagedObjectContext generated");
}
NSLog(#"DelegateApp Managed Object Context = %#", context);
[[DataManager sharedInstance] setManagedObjectContext:context];
[[DataManager sharedInstance] initDataBase];
return YES;
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification) {
[self showAlarm:notification.alertBody];
NSLog(#"AppDelegate didFinishLaunchingWithOptions");
application.applicationIconBadgeNumber = 0;
}
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
[self showAlarm:notification.alertBody];
application.applicationIconBadgeNumber = 0;
NSLog(#"AppDelegate didReceiveLocalNotification %#", notification.userInfo);
}
- (void)showAlarm:(NSString *)text {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"SPOT IT"
message:text delegate:self
cancelButtonTitle:#"YES"
otherButtonTitles:#"NO",nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"NO"])
{
NSLog(#"Button 2 was selected.");
}
else if([title isEqualToString:#"YES"])
{
NSLog(#"Button 1 was selected.");
// attended
[_eachEvent setHasATTENDED:[NSNumber numberWithBool:TRUE]];
// save
NSError *error = nil;
if (![_managedObjectContext save:&error])
{
NSLog(#"Error in saving");
}
}
}
in my DataManager class:
- (void) locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
//NSLog(#"MV_EventsDataManager new location: latitude %+.6f, longitude %+.6f\n", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
for (Event *musicevent in [self loadTodaysEvents]) {
// distance
CLLocationDegrees lat = [musicevent.lat doubleValue];
CLLocationDegrees lon = [musicevent.longi doubleValue];
CLLocation *evLocation = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
double distance = [evLocation distanceFromLocation:newLocation];
//NSLog(#"\t Calculated KM %# to %#", [NSString stringWithFormat:#"%.1f",(distance/1000.0)], musicevent.title);
// CLOSE !
if (distance <= 100) {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"Are u there!";
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = 1; // increment
// NSDictionary *infoDict = [NSDictionary dictionaryWithObjectsAndKeys:#"Object 1", #"Key 1", #"Object 2", #"Key 2", nil];
// localNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
}
Depending on how you setup the location manager, the delegate method locationManager:didUpdateToLocation:fromLocation: will typically be called once per second with location updates. So your code is posting local notifications over and over. You need to keep track of when you've posted a notification so you can avoid posting duplicates.