Ranging and Monitoring Beacons while iPhone is locked and sleeping - ios

So I'm creating an iOS app, and I'm ranging for beacons in the background. It works well once my iPhone is awake and it continues to work even when the iPhone is locked...however the iPhone must still be awake. Once the iPhone goes to sleep my app ranges about 10 more times and then stops. If you wake the iPhone up it starts ranging again.
I've tried monitoring as well but no luck.
Can anyone tell me if this if even possible? I've searched everywhere and can't find an answer! Please find my beacon methods (which are in the AppDelegate) below
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
self.locationManager = [[CLLocationManager alloc] init];
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startUpdatingLocation];
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
if(beacons.count > 0) {
CLBeacon *nearestBeacon = beacons.firstObject;
if (nearestBeacon.proximity == CLProximityImmediate || nearestBeacon.proximity == CLProximityNear) {
NSLog("Beacon detected");
}
}
}
- (void)startRangingBeacons {
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:#"EBEFD083-70A2-47C8-9837-E7B5634DF525" identifier:#"receptionBeacon"];
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
Any help is appreciated
Thanks
Sonia

There is one way to awake your phone. If your app comes under the region of beacon then,
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
above method gets called automatically. So you need to put some local notification like "You are near to beacon zone" to awake the phone.
But you must reenter into the region.
Once your app enter in the region write following code to restart the beacon process,
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
[[UIApplication sharedApplication] endBackgroundTask:UIBackgroundTaskInvalid];
}];
if (bgTask == UIBackgroundTaskInvalid)
{
NSLog(#"This application does not support background mode");
} else {
//if application supports background mode, we'll see this log.
NSLog(#"Application will continue to run in background");
}
Hope this will work for you.

Related

Lifecycle of CLLocationManager for a beacon region monitoring app

I have noticed that whenever I start again the app and look at the following method I get that the beaconRegion returned is not nill. How does this work precisely?
beaconRegion = [self.locationManager.monitoredRegions member:beaconRegion];
// for more context on how I use this please look at the code below
In other words, how does iOS handle the allocation of CLLocationManager? Does it deserialise it every time the app is woken up and in this way retrieve the region information?
This is the output of the Xcode debugger console when running the code below:
2015-11-11 09:44:13.718 RegionMonitoringTest[239:15121] AppDelegate: creating new location manager object
2015-11-11 09:44:13.722 RegionMonitoringTest[239:15121] BeaconMonitoring class: in startRangingForBeacons, startupdatinglocation, range for my beacon
2015-11-11 09:44:13.724 RegionMonitoringTest[239:15121] Region already in list
2015-11-11 09:44:13.732 RegionMonitoringTest[239:15121] AppDelegate: Application did became active.
2015-11-11 09:44:13.762 RegionMonitoringTest[239:15121] BeaconMonitoring -> LocationManager: didFailWithError | Error: Error Domain=kCLErrorDomain Code=0 "(null)"
2015-11-11 09:44:13.762 RegionMonitoringTest[239:15121] Requesting to start ranging for beacons again.
2015-11-11 09:44:13.762 RegionMonitoringTest[239:15121] BeaconMonitoring class: in startRangingForBeacons, startupdatinglocation, range for my beacon
2015-11-11 09:44:13.767 RegionMonitoringTest[239:15121] Region already in list
Below I paste the source code that I am using to test this, it may be helpful (it is based on the AirLocate example provided by Apple):
#import "AppDelegate.h"
#define BEACON_REGION #"01020102-0102-0102-0102-010201020102"
#interface AppDelegate ()
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) NSMutableArray * monitoredRegions;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
NSLog(#"AppDelegate: being woken up after entering region");
}
else{
NSLog(#"AppDelegate: creating new location manager object");
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.pausesLocationUpdatesAutomatically = false;
self.locationManager.allowsBackgroundLocationUpdates = true;
self.locationManager.delegate = self;
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
self.monitoredRegions = [[NSMutableArray alloc] initWithCapacity:10];
[self startRangingForBeacons];
}
return YES;
}
- (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.
NSLog(#"AppDelegate: will resign active");
}
- (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.
NSLog(#"AppDelegate: did enter background");
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
//[self.bluetoothDataSync stopScanning];
NSLog(#"AppDelegate: did enter foreground");
}
- (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.
NSLog(#"AppDelegate: Application did became active.");
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
//[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSLog(#"AppDelegate: App will terminate");
}
//////////////////////////////////////////////////
- (void) startRangingForBeacons{
NSLog(#"BeaconMonitoring class: in startRangingForBeacons, startupdatinglocation, range for my beacon");
[self startMonitoringForRegion:[[NSUUID alloc] initWithUUIDString:BEACON_REGION] :#"my-beaconregion"];
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSString * message = [NSString stringWithFormat:#"BeaconMonitoring -> LocationManager: monitoringDidFailForRegion | Error: %#, Region identifier: %#", error, region.identifier];
NSLog(#"%#", message);
NSLog(#"Requesting to start ranging for beacons again.");
[self startRangingForBeacons];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSString * message = [NSString stringWithFormat:#"BeaconMonitoring -> LocationManager: didFailWithError | Error: %#", error];
NSLog(#"%#", message);
NSLog(#"Requesting to start ranging for beacons again.");
[self startRangingForBeacons];
}
- (void) startMonitoringForRegion:(NSUUID*)beaconUUID :(NSString*)regionIdentifier{
CLBeaconRegion *beaconRegion = nil;
beaconRegion = [self.locationManager.monitoredRegions member:beaconRegion];
if(beaconRegion)
{
NSLog(#"Region already in list");
}
else{
beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID identifier:regionIdentifier];
beaconRegion.notifyEntryStateOnDisplay = YES;
beaconRegion.notifyOnEntry = YES;
beaconRegion.notifyOnExit = YES;
[self.locationManager startMonitoringForRegion:beaconRegion];
}
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
[self.locationManager startUpdatingLocation];
[self.monitoredRegions addObject:beaconRegion];
}
- (void) stopRangingForbeacons{
NSLog(#"BeaconMonitoring: stopRangingForbeacons - Stops updating location");
[self.locationManager stopUpdatingLocation];
for (int i=0; i < [self.monitoredRegions count]; i++) {
NSObject * object = [self.monitoredRegions objectAtIndex:i];
if ([object isKindOfClass:[CLBeaconRegion class]]) {
CLBeaconRegion * region = (CLBeaconRegion*)object;
[self.locationManager stopMonitoringForRegion:region];
[self.locationManager stopRangingBeaconsInRegion:region];
}
else{
NSLog(#"BeaconMonitoring: unrecongized object in beacon region list");
}
}
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (![CLLocationManager locationServicesEnabled]) {
NSLog(#"Couldn't turn on ranging: Location services are not enabled.");
}
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
NSLog(#"Couldn't turn on monitoring: Location services not authorised.");
}
}
#pragma CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"BeaconMonitoring: did enter region, will now start ranging beacons in this region");
[manager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"BeaconMonitoring: did exit region, will now: stop ranging beacons in this region; stop updating locations; stop scanning for BLE");
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
[self.locationManager stopUpdatingLocation];
NSDictionary * notificationData = #{ #"value" : #"exitedRegion"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"dataUpdate" object:nil userInfo:notificationData];
}
- (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
NSString * message = #"CLRegionState: ";
switch (state) {
case CLRegionStateInside:
message = #"CLRegionState: state inside";
break;
case CLRegionStateOutside:
message = #"CLRegionState: state outside";
break;
case CLRegionStateUnknown:
message = #"CLRegionState: state unknown";
break;
default:
message = #"CLRegionState: default case";
break;
}
NSLog(#"%#", message);
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
bool rangedBeacons = false;
if ([beacons count]>0) {
for (int i=0; i<[beacons count]; i++) {
CLBeacon *beacon = [beacons objectAtIndex:i];
if((beacon.major.intValue == 4) && (beacon.major.intValue == 8)){
rangedBeacons = true;
}
}
}
if (rangedBeacons) {
NSLog(#"Region identifier: %#", region.identifier);
NSString * message = [NSString stringWithFormat:#"BeaconMonitoring: ranged a total of %lu, hence request scan start", (unsigned long)[beacons count]];
NSLog(#"%#", message);
}
}
Since Location Manager's monitoring works even when the app is not running, e.g., was terminated due to memory pressure or killed by the user at the app switcher, iOS needs to keep the list of regions apps monitor for somewhere outside the app, and you can think of monitoredRegions as the reflection of that list—rather than an instance property that vanishes when the object gets deallocated.
Note for example that if you instantiate more than one location manager, they all share the same monitoring list—a direct outcome of the list being stored per-app somewhere on the OS level. If you start/stop monitoring for a region in one location manager, it'll affect all the others.
All of this applies to CLBeaconRegion, but also to "regular" CLCircularRegion—because it's a feature of monitoring, and not something beacon-specific.

iOS: Background location app using too much battery

I have an app that gets location updates in the background every 2 minutes and 25 meters traveled. My problem is that while the location tracking is working perfectly, it is seriously draining my battery. Battery usage over a 24 hour period was 30% compared to my next closest app at 14%. Is there some trick to decreasing the battery usage of my app while maintaining my accuracy and time period of location updates?
Could it be draining the battery because of the frequency of calls to didUpdateLocations:? Or could it be that I am communicating with a web service in the background for each location update? I'm really at a loss as to how to improve the battery usage, any help is much appreciated!
Below is my code in AppDelegate for getting location and sending updates to the server:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.locationManager = [CLLocationManager new];
[self.locationManager setDelegate:self];
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
[self initializeRegionMonitoring];
}
-(void) initializeRegionMonitoring {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// notify changes when the device has moved x meters
self.locationManager.distanceFilter = 25; // or set to 20 meters
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[self.locationManager startUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDate *lastDate = [defaults objectForKey:#"lastSavedDate"];
if ([[NSDate date] timeIntervalSinceDate:lastDate] < 120) {
NSLog(#"LAST SAVE TIME LESS THAN 2 MINUTES");
return;
}
[self saveLocation];
//tell the centralManager that you want to deferred this updatedLocation
if (isBackgroundMode && !_deferringUpdates)
{
NSLog(#"THIS IS GETTING CALLED EVERY TIME");
_deferringUpdates = YES;
[self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:120];
}
}
- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {
_deferringUpdates = NO;
}
-(void) saveLocation {
// This code saves location data to a web service
}
- (void)applicationWillResignActive:(UIApplication *)application {
isBackgroundMode = YES;
[self.locationManager stopUpdatingLocation];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[self.locationManager setDistanceFilter:25];
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
[self.locationManager startUpdatingLocation];
}
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return true;
}
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[self saveLocation];
completionHandler(UIBackgroundFetchResultNewData);
NSLog(#"Fetch completed");
}
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[self.locationManager setDistanceFilter:25];
Change these attributes to less accurate. You can save significant battery.
These configurations depends what kind of app it is. If it is some kind of calorie burn app , it might be much accurate. You are updating every 2 minutes , so its should be set on average value of approximate distance covered in time with some threshold.
self.locationManager.pausesLocationUpdatesAutomatically=YES;
//monitor locations for significant location change
[self.locationManager startMonitoringSignificantLocationChanges];
If your app does't require accurate location of the user you can try using significant location change which is more memory optimised way but at the end it depends on the situation what is more important i.e high location accuracy or the battery usage. I have done significant testing on this method and usually it updates the location every 4-5 mins or 500 meters whichever is earliest.

iBeacon events while screen is off

I'm trying to trigger an event based on iBeacons
It works fine when the app is running in the foreground, background but not suspended (screen is turned off with power-button)
I can see the NSLog messages when on the lock screen, but not when the device screen is off.
Is there a way to do this?
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(#"applicationDidFinishLaunching");
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager requestAlwaysAuthorization];
CLBeaconRegion *region;
region = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:#"EBEFD083-70A2-47C8-9837-E7B5634DF524"] major: 9 minor: 103 identifier: #"region1"];
region.notifyEntryStateOnDisplay = YES;
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
[_locationManager startMonitoringForRegion:region];
[_locationManager startRangingBeaconsInRegion:region];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
if(state == CLRegionStateInside) {
NSLog(#"locationManager didDetermineState INSIDE for %#", region.identifier);
}
else if(state == CLRegionStateOutside) {
NSLog(#"locationManager didDetermineState OUTSIDE for %#", region.identifier);
}
else {
NSLog(#"locationManager didDetermineState OTHER for %#", region.identifier);
}
}
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
if ( beacons.count > 0 )
{
NSLog(#"locationManager didRangeBeacons: %#",beacons.description);
}
}
Info.plist (relevant section only):
<key>NSLocationAlwaysUsageDescription</key>
<string>app location requested</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>voip</string>
<string>bluetooth-peripheral</string>
<string>bluetooth-central</string>
<string>external-accessory</string>
</array>
Set pausesLocationUpdatesAutomatically property of LocationManager to "NO", With this property set to NO location services are never powered down. But you have to be careful, as setting this property to NO significantly increases the power usage of the device.
While beacon monitoring (didEnterRegion: and didExitRegion:) works in the background, beacon ranging (didRangeBeacons:inRegion:) only works when the app is in the foreground, and for a limited time in the background. These background limits include five seconds after the app is woken up into the background due to an event (like lock screen coming on due to your setting region.notifyEntryStateOnDisplay = YES;)
There are some tricks you can do to get extra background ranging time. Read here:
http://developer.radiusnetworks.com/2014/11/13/extending-background-ranging-on-ios.html

iBeacon monitoring/ranging after device restarts

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.

recieving location updates after app is terminated

I need to keep track of the user location all the time (but not drain the battery).
I understand the only way to get updates after app is terminated is using startMonitoringSignificantLocationChanges.
From Apple's Location Awareness Programming Guide on startMonitoringSignificantLocationChanges:
If you start this service and your application is subsequently
terminated, the system automatically relaunches the application into
the background if a new event arrives. In such a case, the options
dictionary passed to the application:didFinishLaunchingWithOptions:
method of your application delegate contains the key
UIApplicationLaunchOptionsLocationKey to indicate that your
application was launched because of a location event. Upon relaunch,
you must still configure a location manager object and call this
method to continue receiving location events. When you restart
location services, the current event is delivered to your delegate
immediately. In addition, the location property of your location
manager object is populated with the most recent location object even
before you start location services.
I would be glad if someone could demonstrate in the code (give an example) which methods i should use
In the following code i'm tring to :
- start the location manager at appdelegate which strats the signinficant monitor changes update and startupdating.
- in didUpdateToLocation i'm calling stopupdating
- in didFinishLaunchingWithOptions when i check if i got a UIApplicationLaunchOptionsLocationKey in order to know if i'm in the background and launched due to siginificant monitor location update.
- if so, i call startMonitoringSignificantLocationChanges again (not sure why...)
and begin a UIBackgeoundTaskIdentifier for calling startupdating method.
LocationController.m :
+ (LocationController*)sharedInstance {
#synchronized(self) {
if (sharedCLDelegate == nil) {
[[self alloc] init];
}
}
return sharedCLDelegate;
}
- (id)init
{
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[self.locationManager startUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
return self;
}
- (void) startMonitoringSignificantLocationChanges
{
[self.locationManager startMonitoringSignificantLocationChanges];
}
- (void) stopMonitoringSignificantLocationChanges
{
[self.locationManager stopMonitoringSignificantLocationChanges];
}
-(void) start{
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 30) {
self.lastLocation = newLocation;
[self updateLocation]; //sending location to server
[self.locationManager stopUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager*)manager
didFailWithError:(NSError*)error{
[self.locationManager stopUpdatingLocation];
}
AppDelegate.h :
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIBackgroundTaskIdentifier bgTask;
}
AppDelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
id locationValue = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey];
if (locationValue) {
[[LocationController sharedInstance] startMonitoringSignificantLocationChanges];
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
[[LocationController sharedInstance] start]; //startupdating
return YES;
}
else {
[[LocationController sharedInstance] init];
}
}
-(void) applicationDidEnterBackground:(UIApplication *) application
{
NSLog(#"entered background Mode");
}
-(void) applicationDidBecomeActive:(UIApplication *) application
{
NSLog(#"application Did Become Active");
}
Thank you.
Using your classes, this is what I would do.
In your AppDelegate.m, when your app is in the foreground or background, I'd move the CLLocationManager to run in the foreground / background to match. The reason I'm doing this is because if the CLLocationManager is not moved to the background when the app is in the background, no location updates are sent to the CLLocationManager's callback
- (void)applicationDidEnterBackground:(UIApplication *) application {
[[LocationController sharedInstance] stop];
[[LocationController sharedInstance] startMonitoringSignificantLocationChanges];
NSLog(#"entered background Mode");
}
- (void)applicationDidBecomeActive:(UIApplication *) application {
[[LocationController sharedInstance] stopMonitoringSignificantLocationChanges];
[[LocationController sharedInstance] start];
NSLog(#"application Did Become Active");
}
So lets say your app then moves to the background, and after awhile, iOS decides it's using too much memory and kills your app.
A few minutes later, iOS then receives a location update, and respawns your app, letting it know it respawned due to a location service. You then need to re-start the background location service, as it will be the only chance your app has to do so.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
[[LocationController sharedInstance] startMonitoringSignificantLocationChanges];
}
return YES;
}
Oh, and one last change, I'm not sure why in your locationManager:didUpdateToLocation:fromLocation: method you're stopping the location service, as when you do that no more updates come through. Just leave it running, then every time a location change comes through you can send that to the server.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 30) {
self.lastLocation = newLocation;
[self updateLocation]; //sending location to server
}

Resources