iBeacon monitoring implementation ios7.1 - ios

I’ve a problem about iBeacon monitoring implementation. I fire a local notification when locationManager:didDetermineState:forRegion: method is called. When application goes in background I don’t get any local notification at all but they came all at once when I active the screen pushing the home button. According to time I leave sleep the device I can get up to tens notification always when I wake it up. How is that possible? Anyone had the same problem?
I use iPhone 5S and 5C with iOS 7.1. The local notification is set in this way:
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
UILocalNotification *localNot = [[UILocalNotification alloc] init];
localNot.alertBody = [NSString stringWithFormat:#"Region state %d determined", state];
localNot.alertAction = #"Go for it!";
localNot.soundName = UILocalNotificationDefaultSoundName;
localNot.fireDate = nil;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNot];
}

I suspect that you are not actually doing any background detections at all, and the reason you see the notifications when you hit the home button is because you have the notifyEntryStateOnDisplay flag set, which causes you to get an extra callback to didDetermineState: forRegion: whenever the screen comes on, for every region you are monitoring with the flag set.
Why do you not get callbacks in the background? You may need to wait up to 15 minutes to detect an iBeacon in the background, even on iOS 7.1. See here.

Related

didExitRegion: 1.5 to 2 minute delay of called when my application is killed or in background in ios 10

i have to use estimote location beacon,iphone 5s,ios version 10.
didEnterRegion: method also called 30 to 40 seconds delay.
i have to use below code for monitoring ibeacon.
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"CFC52BF4-FD33-4569-B4B5-5E9C220514A2"];
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:1 identifier:#"Technostacks23"];
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
// launch app when display is turned on and inside region
region.notifyEntryStateOnDisplay = YES;
if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
{
[_locationManager startMonitoringForRegion:region];
[_locationManager startRangingBeaconsInRegion:region];
}
[self.locationManager startUpdatingLocation];
#pragma mark - CoreLocation Delegate method
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
//local notification fire
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
//local notification fire
}
please guys tell me how to tackle this scenario.
Thanks
I don't think you can monitor a region at the same time you are ranging. I had this problem on a screen I made where I wanted to show the user if they are in range of the Beacon. I had to stop monitoring until they left the screen, then restart monitoring. If you don't need the events for ranging (how close the user is to the Beacon), I would leave that line off, it isn't necessary to get -didEnter and -didExit calls. You also shouldn't need -startUpdatingLocation either. That is only for active location calls.
Entry events typically fire right away. Exit events do have a 20-30 second delay once you lose signal to the Beacon.
It may be that you are burning up your background run time monitoring, after you run out of time it stops, opening the door for you get monitoring events.
Call the startRangingBeaconsInRegion method in the didEnterRegion delegate method so it wont range for beacons when it is not already in the beacons region this will help in power and battery consumption and i believe it would speed up region detection a little bit.
Edit your advertising interval of the beacon make it 350ms or less.
Check in your iPhone Settings tab for the apps that allow background App Refresh and Location Always and just reverse them to don't allow and make a test see if there would be a difference in detection performance.
But in all cases the 30 - 40 sec delay i find it normal depending on the number of apps that are already processing in the background and running out resources plus it would be even better depending on your app model to start notifying for a region entry after a couple of seconds to make sure also that he is in the region and didn't just pass by so quickly "Im talking for a super market model for instance".
But if this is not your case and you want to detect a region just by passing by i think the fastest you can get will be 15 - 20 sec depending on your device capability, speed, other background processing apps, and the beacons advertising time interval.

iBeacon-App: Custom code when launched from lockscreen

Since iOS 8, the operating system is indicating an iBeacon-enabled application, which is inside a defined region, with an icon in the left bottom corner of the lockscreen (see http://appleinsider.com/articles/14/06/03/apples-ios-8-uses-ibeacon-tech-brings-location-aware-app-access-to-lock-screen for reference).
I want to make use of this feature in my app by running custom code if the app is launched from the lockscreen (e.g. switch to specific view).
How to check in the Application Delegate if the app was launched from the lockscreen? I couldn't find any documentation on this.
AFAIK, it's not possible to detect whether your app was brought into the foreground via the "Suggested apps" feature (that's what Apple calls the icon on the lock screen), or by any other means (app switcher, app icon on the home screen).
You could do some heuristics. If the app came into the foreground and there are no beacons in range (you can check that with ranging), then there's no way it was via the lock screen icon.
There is a Excellent article on this topic by Matt Coneybeare
Below I have pointed out some of the important points from that article , for more info check out that article.
From Article of Matt Coneybeare
On iOS 6 and lower it could be detected using the current UIApplicationState in applicationWillEnterForeground
UIApplicationState state = [[UIApplication sharedApplication] ApplicationState];
if (UIApplicationStateInactive == state)
// Coming from locked screen (iOS 6)
else
// Coming from Springboard, another App, etc...
But From iOS 7 onwards, the state value is UIApplicationStateBackground in both scenarios.
It seems that there is no possible way to detect where the App is being launched from on iOS 7, but there is a way to detect if you are going to the Lockscreen vs Homescreen (or something else).
The trick is to read the screen brightness in applicationDidEnterBackground.
When the App hits the background due to the lock button being pressed or an auto-lock timeout, the brightness will be 0.0 on iOS 7.
Otherwise, it will be > 0 when the home button is pressed or another App launched from the multitask selector or notification center.
When the app is launched by beacon detection, your AppDelegate's (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region method will be invoked.
You can put any custom code inside that method, perhaps to set a flag indicating this is how the app was launched.
The following code shows how to detect that tapping a local notification launched the app from the lock screen. For details, see: https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
// do something
}
...
return YES;
}
This is not the same as launching the app by tapping the icon on the bottom of the lock screen, but it is similar. If you present a local notification on beacon detection it will work as described above if tapped.
I believe the app icon shows up on the bottom of the lock screen only if your app is launched into the background by beacon detection and does not present a local notification. If this is the case you are looking for, you might examine the launchOptions above and see if a different key is present in this case.

iBeacon ranging in the background?

I have started to test out iBeacons using estimotes as beacons.
It's all running pretty good, but i'm struggling with getting the app to run properly in the background.
self.region = [[CLBeaconRegion alloc] initWithProximityUUID:self.uuid identifier: self.deviceID];
self.region.notifyEntryStateOnDisplay = YES;
[self.locationManager startMonitoringForRegion:self.region];
So this is the basic setup and for my test app i want to show a local notification when my phone is in immediate proximity of the beacon. My problem is that it won't work unless i include the line below.
[self.locationManager startUpdatingLocation];
Can anyone explain why that is or if i'm missing something about iBeacons?
You are mistaken. You don't need to call startUpdatingLocation in order to be called in the background.
When you're in the background it takes longer to get notified when you enter a region. If you want ranging calls, you have to issue the startRangingBeaconsInRegion call as well. As the other poster pointed out, you will only get a few seconds of ranging calls from the background when a new beacon is detected. (You get a didEnterRegion, followed by a few ranging calls, and then your app goes back to sleep.)
No, you are not missing anything. In background you app gets a very small amount of time to do ranging. From my personal experience, you get about 3 to 5 ranging callbacks. Thats it.
You do not need to call startUpdatingLocation method.
startMonitoringForRegion method starts monitoring the region only and call the didStartMonitoringForRegion delegate method to let you know when beacon enter/exit the region.
You need to call startRangingBeaconsInRegion method, which calls didRangeBeacons delegate method which gives you array of detected beacons with UUID, major, minor, rssi info of beacons.
For background execution, just use UIBackgroundTaskIdentifier and your code will work in background as well.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"=== DID ENTER BACKGROUND ===");
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
}];
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");
}
}

didRangeBeacons method not getting called when display is Off

i'm working with ibeacons from couple of weeks, i was trying to post some local notifications , when the iphone hits the beaconregion(when proximity near).
It was working fine when the app is in background with locked and with display on, but when my display turns black ,
didRangeBeacons method stopped getting called.
I know by using the
region.notifyEntryStateOnDisplay = true;
we can get notified while the display on.
Is there any way that i can achieve posting notification while the app is background with locked and display off.
Please help me out.
It is totally possible to range beacons in background.
You can go around the limitation by setting this up together with your current location manager or creating a parallel one (which makes no difference, I think). You'll also need to enable background location updates capabilities at your project.
locationManager2 = [[CLLocationManager alloc] init];
locationManager2.delegate = self;
locationManager2.desiredAccuracy = kCLLocationAccuracyKilometer;
[locationManager2 startUpdatingLocation];
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
//Do nothing here, but enjoy ranging callbacks in background :-)
}
Now, you'll need to have a good explanation when Apple ask you why do you need the background location updates mode in your app. They're very picky with that.
If you have requested both beacon entry notifications and ranging, and you ENTER a new region while the screen is locked, you will get a didEnterRegion message (or possibly the didDetermineState message) followed by about 5 seconds of ranging messages. If the user doesn't wake up the device during those 5 seconds, the ranging messages stop.
Thus you can't really filter based on proximity to a beacon from the background. If you try to wait until you get a range value of near then more than likely you won't get it because the device stops sending your ranging messages before the user gets that close. You then won't get any more notifications about that beacon region until the user either leaves the region again or wakes up the phone and brings your app back to the foreground.
An app I'm working on posts a local notification when it receives a didEnterRegion (or didDetermineState) message. That causes the screen to light up, but doesn't seem to extend the amount of time you get ranging notices.
No, this is by design and reflects iOS's goal of conserving battery. You can only count on didRangeBeacons: while the app is foregrounded.
David Young has a pretty thorough writeup that may help clarify.
I have the same problem which Madhu has. Instead of didUpdateToLocation, I used didUpdateLocations which is worked for me. Now I am able to range beacons while the app is in background or terminated with locked and display off.
On iOS 8.4
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
//Do nothing here
}

Keep GPS running for a few minutes when pressing the Home button

I have an App with Region Monitoring but for better presition I call to "startUpdatingLocation" for use the GPS when the user enter into the Region specified:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
[manager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
locationManager =manager;
CLLocation *location1 = locationManager.location;
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:obj.latitude longitude:obj.longitude];
float betweenDistance=[location1 distanceFromLocation:location2];
if((betweenDistance/1000)<=0.350000){
// Fires an UIAlert
}
}
That works fine in the most of cases, for example if the user is outside the region and then press the "Home Button" and after enter into the region fires the function "didEnterRegion" and the GPS starts to work for a few minutes and show the Alert, thats the right way.
But if the App is open and then the user enter in the region fires the function "didEnterRegion" and the GPS starts, but if the user press the "Home Button" in that moment the GPS stops and the Alert never appear.
I don't want to activate the option of "Required Background modes" in the info.plist because I only want to use GPS for a few minutes after the user press de Home Button, and not for to use in a excesive mode.
Any ideas?
When your application delegate gets the message applicationWillResignActive: you can request that the OS keeps your app running by creating a request like this:
UIBackgroundTaskIdentifier taskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// do you cleanup in here if your background task gets terminated by the system
}];
After that, your event loop will keep running and you'll continue to receive events like normal (except your app's window isn't visible, so you obviously won't receive touch events or other window-related events).
Once you no longer need to be kept running you can release your request like this
[[UIApplication sharedApplication] endBackgroundTask:taskID];
To make it all work, just add a flag to your app delegate to let it know when you're doing something that requires more time. Then, when your delegate gets the applicationWillResignActive: message it can check that flag and, if it's set, request some background time to keep running.

Resources