I'm doing some test using estimote beacons and regions.
Reading the documentation as I start monitoring a region I'm going to tell my delegate that a specific region is being monitored, however, didEnterRegion and didExitRegion are never fired.
My delegate fires:
-(void)beaconManager:(ESTBeaconManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(ESTBeaconRegion *)region
and
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
I didn't check if an error occurs into locationManager:didFailWithError:
At the moment I'm using the state to manually run two private methods that work as didEnter and didExit - in this case I'm also able to monitor the region but I didn't get why locationManager:didEnterRegion: and locationManager:didExitRegion: are never called.
Is someone facing the same behavior?
There are several items to check. The one that addressed my problem was Enabling Background App Refresh in your device's settings (see screenshot below). I had this disabled as a battery saving measure. Monitoring will not work if this is disabled.
If this doesn't address your problem there is a great post you can read that details all of the items to troubleshoot.
iBeacon StartMonitoringForRegion Doesn’t Work
This should work. I would like to see the rest of your code that sets up the monitoring, and I would put NSLog statements in your didEnterRegion didExitRegion and didDetermineState (log the state value, too).
It could be that iOS thinks no region transitions are occurring -- that you are always "in" the region, thus no transition. Transitions can take up to 15 min to occur in the background (although if you are ranging in the foreground it should be within 4 secs for an "out" and 1 sec for an "in". See http://developer.radiusnetworks.com/2013/11/13/ibeacon-monitoring-in-the-background-and-foreground.html
You can force an in/out region callback by setting region.notifyEntryStateOnDisplay=YES; on your monitored region, then hit the shoulder button. This should force monitoring callback. If you do this and don't see the log statements I suggested adding above, I would be very surprised.
I've tried almost everything and it didn't work.
Then I simply restarted my iPhone...and it started working. Incredible.
I had this problem with Estimote Beacons.
Related
Since yesterday, I have a problem with monitoring region working with CLLocationManager
PS: my project was working perfectly I'm testing it everyday, but today this delegate method was called after 1 minute of entering a region
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{}
and now it's no more getting called I have made another project only with CLLocationManager for testing the delegate method and the same thing is happening.
Can you just tell me what the hell this could be?
[UPDATE]
i found this helpful link about iOS Region Monitoring after iPhone Restart
Just check that below service is on or off.
[CLLocationManager regionMonitoringAvailable] returns YES
CLLocationManager.monitoredRegions contains valid regions
Apple document specified that events make take between 3-5 minutes to fire.
Hope this help you.
Does locationManager:didDetermineState:forRegion: get called?
Do you call requestStateForRegion: after startMonitoringForRegion:?
Is this in background or foreground?
We are doing some work with beacons and iOS and investigating the options for applying a debounce between when we first go in range of the beacon and when we raise a notification to the user.
So the flow would be,
Go in range of a beacon.
Start a timer.
Timer expires, post notification.
Their doesn't seem to be any complications doing this when the app is in the foreground but I'm not sure how this will work with the app closed.
If we register the location background mode then the app will get started when we go in range of a beacon but its unclear to me how long the app we'll be allowed to run. If the app is only allowed to run for a very short period of time then we won't have time to start a timer and have it expire.
Can anyone shed any light on how much execution time the location background mode allows an app when started in the background like this?
I would suggest that once you enter the beacon region that you start ranging the beacon - this will provide you with ranging callbacks at the rate of one per second - even if your app is in the background. You can count these events and use that to determine when you will post the notification. At this point you can stop ranging the beacon.
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
[manager startRangingBeaconsInRegion:(CLBeaconRegion *)region];
self.beaconCount=0;
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
}
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region {
self.beaconCount++;
if (self.beaconCount > SOME_THRESHOLD) {
[manager stopRangingBeaconsInRegion:region];
[self postLocalNotification];
}
}
Because this is using the location background mode there is no overall limit to the amount of background time available, but there is a limit on each invocation of a delegate method of a few seconds - but this code won't be anywhere near that.
You can use local notifications for this purpose. There is no guarantee how long your app will continue running in background. If you want to know how much time the OS gives you, you can check UIApplication's backgroundTimeRemaining property.
https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/index.html#//apple_ref/occ/instp/UIApplication/backgroundTimeRemaining
I am accessing Gelo iBeacon,Its working fine in foreground mode but how to get ibeacon range or region monitoring when the app is in background mode.
Thanks in advance
Generally iOS lets you monitor for beacons in the background but not range for them. Ranging only works in the background for a few seconds after a monitoring event.
Details on detection times and steps needed to set up background monitoring are here.
Use the following method it will work for background as well as background
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
You need to make sure you ask for always access to location manager.
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
DO NOT use "Location Updates" or "Uses Bluetooth LE accessory" as this might result in rejection from the app store. We are not using ranging, but just monitoring, and this worked fine for us.
I am working on a location services app and am finding some strange behavior. Once the user confirms using location services, the geofence icon appears in the status bar. Everything works great and I get enter and exit region events whether the app is running, in the background, or not in the background. But at some point the geofence icon disappears and my device is insensitive to the Beacon. Are there any conditions under which the geofence is disabled until I power cycle the device? And power cycling does bring it back.
This is a newly introduced bug in CoreLocation. Unfortunately, there is no known automated way to fix this. It requires a power cycle or Bluetooth off/on sequence to resolve.
See here.
I was having a similar problem. My app would work and locate beacons on initial run. When I rebooted, app opened to ScanViewController as expected but did not detect beacon.
I referenced article on StackOverflow, iBeacon: didRangeBeacons stops getting called, must reset device for it to work again and reviewed Apple's WWDC 2013 Video Session "What's new in Corelocation" https://developer.apple.com/videos/wwdc/2013/index.php?id=307
I found additional CLLocation delegate methods:
When you init your beacon region if you set:
notifyEntryStateOnDisplay = YES;
//The following delegate method will be called:
-(void) locationManager: (CLLocationManager *) manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
if (state ==CLRegionStateInside) {
[_locationManager startRangingBeaconsInRegion:region]:
}
//Your alternative code
}
//To help trouble shoot, I added this delegate methods
-(void) locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *) region withError: (NSError *)error {
}
and
-(void) locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLRegion *) region withError: (NSError *)error {
}
I ran app. It returned no failure errors. I checked settings. Bluetooth was enabled and detecting BT devices.
I checked the status bar for geofencing icon. The geofencing icon was present.
I waited for over 2 minutes and then the app detected the beacons and worked as expected. Sluggish is an understatement. I knew that rebooting should work according to all the iOS 7.1 articles that I read in StackOverFlow and other resources.
I rebooted and waited for the app to detect the beacons. On average it took 2 minutes until beacon detection. I am not sure what is causing this slow response. Since must app responses are measured in fractions of seconds, I am sure that developers may think that their apps are not working.
I suggest if your app does not detect beacons or return failure errors that you wait 2 minutes to see if you app will detect the beacon(s). I hope this helps.
Testing Device: iPhone 5 (iOS 7)
I have an app that uses RegionMonitoring and updateLocation. If a region is entered, didEnterRegion is called as expected. Then I call startUpdatingLocation. But the method didUpdateToLocation is only called 10-20 times while it should update the location until the timer fires.
The relevant code:
CLLocationManager *_locationManager;
NSTimer *_timer;
-(void)initLocationManager
{
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager setActivityType:CLActivityTypeOther];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[_locationManager setPausesLocationUpdatesAutomatically:NO];
[_locationManager setDistanceFilter:kCLDistanceFilterNone];
}
//Did Enter Region, called as expected:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
[_locationManager startUpdatingLocation];
_timer = [NSTimer scheduledTimerWithTimeInterval:300.0f target:self selector:#selector(scheduleMethod:) userInfo:nil repeats:NO];
}
//Timer Fire Method:
- (void) scheduleMethod:(NSTimer*)timer
{
[Utils writeToLog:#"Timer-Stop"];
[_locationManager stopUpdatingLocation];
}
//This Method only called 10-20 Times (in the first 10-20 Seconds) and not the complete 5 Minutes:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[Utils writeToLog:#"LocationUpdate!"];
}
So far I tried:
Restarting the Updates in the locationManagerDidPauseLocationUpdates method, but it seems that this is never be called:
-(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager
{
[WRUtils writeToLog:#"LocationUpdate paused, restarted"];
[_locationManager startUpdatingLocation];
}
Check for errors in the didFailWithError method, but this is not called either.
And played a bit with the properties:
[_locationManager setActivityType:CLActivityTypeOther];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[_locationManager setPausesLocationUpdatesAutomatically:NO];
Plist settings are right I guess:
Required background modes YES
Required background Modes
Item 0 App registers for location updates
How can I solve this?
Apple has introduced a new policy in iOS 7. iOS 7 does no longer deliver location updates in the background if you call „startUpdatingLocation“ while the App is in the background. You only get update when the App is brought to the foreground in this case.
When you’re using the geofencing feature, your App just gets a few seconds each time you get a RegionEntered/Exited notification to process this notification. And in these few seconds you may also get location updates. After these few seconds are over iOS 7 just suspends your App again.
You can use background task to get more than just a few seconds, but in iOS 7 Apple has also reduced the time Apps can run in the background from 10 minutes (iOS 6 and older) to only 3 minutes under iOS 7. It looks like that these 3 minutes are the total amount for the whole time the App is in the background. Which means you can not ask iOS 7 10 times to get 1 minute background time, you’ll only get 3 minutes in total, so after the 3rd time you’ve asked for a minute, your App won't get any background time anymore at all.
Your only chance in getting location updates in the background is to call „startUpdatingLocation“ while the App is in the foreground. This is sad especially when you only need location updates in response to Region(Enter/Exit messages, because you need to let the location updates running all the time. But you can at least reduce the battery usage by setting the accuracy value to kCLLocationAccuracyThreeKilometers when
you do not need location updates and set the accuracy to kCLLocationAccuracyBest only when you really need the geo coordinates. The iOS won’t power up GPS for the kCLLocationAccuracyThreeKilometers value, so the battery usage would be moderate in this case.
Also the value kCLLocationAccuracyBestForNavigation for the accuracy seems to cause problems under IOS 7. I do not get any location updates with this value if the device is not connected to a an external power supply.
All in all the new iOS 7 policy for location updates is making it much harder to develop certain kinds of Apps. Instead of registering for location updates only when needed, you are forced to register for these for the while lifetime of your App. Which of course drains the battery a little bit faster, though Apple’s intension for this new policy was probably the opposite.
UPDATE:
After some more testing I’ve found some kind of solution for the problem.
The docs from Apple mention that when using the Significant Location Change API, Apps can receive location updates in the background even if „startUpdatingLocation“ is started in the background.
My first tests didn’t work well. I was registering my App for significant location updates within the region monitoring delegate methods just before calling startUpdatingLocation (so this location service is only enabled when needed), but this still does not deliver location updates in the background as the docs would suggest.
But if you start listening for significant location changes directly after your App is launched (and never switch this off), you can call start „startUpdatingLocation“ while the App is in the background and also receive location updates in the background. The battery usage of having the "significant location change“ feature on all the time seems to be very low, so this will be probably the solution for most Apps.
You have to check if the „significant location change“ feature is available on the device, but it seems that all current devices do support this. Even the 5th generation of iPod Touch does support it (The iPod Touch can not use cell towers for location updates, which is the base method of this feature according to the docs from Apple, so I guess we can assume that all current devices running iOS 7 can use the „significant location update“ API. Though it’s probably a good idea to check if this feature is really available, maybe there are certain circumstances where the feature is not available).
Using the "significant location change“ API might have one disadvantage: The App can be launched in the background (if it was terminated in the background by the iOS to reuse its memory for other Apps) repeatedly and unnecessarily whenever the device has moved „significantly“ (according to the docs: when the cell tower has changed, but no more than once per 5 min). So Apps which only need to be activated, when a certain region is exited or entered, will be launched and informed about location changed all the time, not only at those regions. But I assume this should be still much better than having standard location updates active all the time.
My iPhone 5s drains the battery only 1% over night with the significant location changes active, instead of 12% with having the standard location updates active with the accuracy set to 3km.
Hope this helps all developers who are struggling with the new iOS 7 behavior.
In background timer will not run, so here your timer object will not respond, You need to create background task handler, check comment of below link,
How to run the timer in background of the application?
In background if you want to continue location service than you need to set pausesLocationUpdatesAutomatically flag, flag info on
pausesLocationUpdatesAutomatically flag info
if ([self.locationManager respondsToSelector:#selector(pausesLocationUpdatesAutomatically)]) {
self.locationManager.pausesLocationUpdatesAutomatically = NO;
}
check my comment on
Location service going to "Inactive" state in iPhone 5
For location manager there below are the CLLocationManagerDelegate methods for location update,
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation [Deprecated in __IPHONE_6_0]
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0);
Where you found
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation ??
Use below code in your didEnterRegion Method to start updates again
[_locationManager startMonitoringSignificantLocationChanges];
if ([_locationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
{
_locationManager.allowsBackgroundLocationUpdates =YES;
}
[_locationManager startUpdatingLocation];