Ranging beacons in background - is that possible?

Hi there!

I would be really happy if my application could detect beacons in background mode. And not only get notified when they are around but I would like to know when they are in a specific proximity. I know about some possible solutions, but none of them meets all my requirements. I would love if some of Estimote experts in this forum showed me if I get something wrong :smile:

SOLUTION 1. Region monitoring.

This is nice, clean and works in background perfectly. However, it doesnā€™t take proximity into account. If I want to get notified in background that Iā€™m very close to the beacon, I canā€™t do that, because I get notified about this beacon once I enter its region and it can be far away. And as I get closer and closer, I wonā€™t get any new background notifications.

SOLUTION 2. Region monitoring + setting different power levels for every beacon.

This would solve my problems but in my application it would be extremely cumbersome to set power level for every beacon separately. Thats why I rule out this option.

SOLUTION 3. Ranging

Ranging is proximity-aware. But it doesnt work in background :frowning: I know I know, battery life.

SOLUTION 4. Ranging + Location enabled

It turns out (I know it from this forum btw, thanks!) that ranging actually does work in background. If we turn on Location updates in CLocationManager, and start ranging, then didRangeBeacons delegate method will be called everytime the didUpdateLocations method gets called. It really worked for me, but there are some drawbacks of this solution:

  1. Sometimes, when my application goes to background, didUpdateLocation doesnā€™t get called at all. Therefore, didRangeBeacons is not called too. Do you know why this happens?
  2. This behaviour is clearly not what Apple intended, so I cannot be sure if this option wonā€™t be removed in the future versions of iOS.
  3. I havenā€™t tried to pass this solution through review (mainly beacause of 1. limitation) but I suppose it could be really hard to.

SOLUTION 5. CoreBluetooth Based Scanning: startEstimoteBeaconsDiscoveryForRegion

I was very hopeful about this one. I read that it works in background (we must turn on bluetooth-central background mode ofc) but unfortunately, it didnā€™t work well for me:

  1. Most of the time, it worked in background only about 10 seconds and then stopped.
  2. This method detected 1 out of 3 beacons nearby.

Actually, results of didDiscoverBeacons delegate method were pretty strange and unpredictable, so I assumed I shouldnā€™t use it too.

Summary

None of the solutions is 100% OK. I wonder if there is some other option or maybe I miss something in above mentioned options. I would really love to get it work!

Iā€™m waiting for your insights guys!

Just wanted to briefly comment on background ranging:

As you mentioned, itā€™s technically possible, but we stronlgy advise against it. Apple is very reluctant to let apps utilizing this through review, mainly due to battery life and privacy concerns. So if you do give it a shot, during the review process you need to be vert clear about how this is going to benefit the end user. Weā€™ve written a bit more about this righr here: https://community.estimote.com/hc/en-us/articles/203914068-Is-it-possible-to-use-beacon-ranging-in-the-background-

Cheers.

Adding to what Wojtek said: developers who know tried this and put their apps up for review were indeed mostly faced with rejections. Some of them managed to clarify the background ranging to the review team and eventually had their apps approved. So itā€™s not a lost cause.

One addition to Solution 1: when didEnter gets triggered, iOS grants your app ~10 second of background execution time, which you can use to show a notification, ping a backend, but also ā€¦ start ranging. Your app will go back to sleep after 10 seconds, pausing ranging until itā€™s woken up again. You can prolong the 10-second period by starting a background execution task. Apple gives no guarantees as to how long these can run ā€“ empirically speaking, iOS 8 seems to limit these up to 3 minutes.

TL;DR, with some (legit!) advanced techniques, you can range for up to 3 minutes in the background once didEnter wakes the app.

Thank you for your answers, they are great!

You gave me some hope. I know that it would be hard to let background ranging through review, but I have really good explanation for that in my app. And I have a strong mechanism of turning it on only when necessary to minimise battery draining. The question is: do you know why, sometimes, my application doesnā€™t get location updates in background? The same code, in the same environment, sometimes gets those updates, sometimes donā€™t. Can it be caused by the fact that maybe GPS sometimes cannot fix? I always used kCLLocationAccuracyBest.

A little note about privacy: It shouldnā€™t be a concern, if Apple already lets user location be tracked by GPS, should it? Of course, user should allow for it. It would be just an indoor version of location tracking.

And funny thing is that I donā€™t actually care about ranging every second, I would even prefer not to do it (because of battery usage). Monitoring would be much better for me, but without proximity, itā€™s pretty much useless anyway.

Iā€™m curious which way Apple will take. Without ranging in background, precise beacon-based indoor location wonā€™t be possible in background.

Hi r00dY, Iā€™m currently working on a project that requires constant background ranging(3 minutes probably wonā€™t be enough for our use case) and have been faced with the same issue.

At the moment Iā€™m using the same solution that you mentioned(number 4.) with the startUpdatingLocation method and am hoping that we can get it submitted to the App store with no trouble when itā€™s finished. I currently have desiredAccuracy set to kCLLocationAccuracyThreeKilometers to help reduce battery drainage.

You mentioned that you have ā€˜a strong mechanism of turning it on only when necessaryā€™, could you elaborate on this? From what Iā€™ve seen (in the comments section of this link: http://ibeaconmodules.us/blogs/news/14279747-tutorial-ibeacon-app-development-with-corelocation-on-apple-ios-7-8) if you stopUpdatingLocation(eg. after leaving a region) and then restart at another point in the code and the app will only give you a few ranging events before going back to sleep(as opposed to when itā€™s started for the first time and will constantly give ranging events), so basically I have to have startUpdatingLocation constantly activated for constant updates.

Best of luck,
Sam

Iā€™m working on an app with a similar use case. I found this thread specifically looking for something on background ranging. Similar to @r00dY , I do not really need background ranging, per sĆ©, I just need something that can wake up the phone at a particular point in time, allowing me to check if I should start ranging. I had ruled out the location update API because I was pretty sure itā€™d get rejected, but perhaps with intelligent use of receiving location updates and good enough explanation, it could make it through.

Itā€™s worth noting, this seems to be important if iBeacon usage at home ever takes off. I canā€™t go anywhere in my home and actually get an didExitRegion to trigger. Therefore I have no choice but to rely on ranging to determine proximity. With the M7 sensors, I can be somewhat intelligent about when to turn ranging on/off, but unfortunately, M7 activity does not wake my app up in the background. Therefore, it seems weā€™re stuck with location updates for home use.

My beacon is a custom Raspberry Pi iBeacon at the moment, would an Estimote beacon or sticker be less powerful?

So I implemented background ranging today using a the location + ranging technique. Hereā€™s how I have it working that I think will use minimal battery but still solve the ā€œat homeā€ use case:

  1. When the app starts in the foreground, itā€™s business as usual: just monitoring/ranging like you normally would without any location updates
  2. When the app is about to go into the background, applicationWillResignActive gets called, and in there I stop all of my beacon listening, I set desiredAccuracy to kCLLocationAccuracyThreeKilometers and call startUpdatingLocation and then start the beacon monitoring/ranging again
  3. In didExitRegion, I stop all beacon monitoring/ranging again, call stopUpdatingLocation followed by startMonitoringSignificantLocationChanges to really conserve battery, but to make sure that didEnterRegion still gets called when I come back home (n.b. I donā€™t actually have this part fully working yet, so no promises)
  4. In didEnterRegion, I once again stop beacon listening (just in case), stop monitoring significant changes, call startUpdatingLocation and start beacon listening again

Using the 3km desired accuracy setting, Iā€™m only ever getting a single location update, but my app stays running in the background. Itā€™s not using much battery (I tested it with the Energy Consumption instrument and the overall energy usage was very low over 30 seconds of background running, and the GPS never turned on). To be safest, Iā€™m switching to significant change monitoring outside the region since I donā€™t need the app to wake up until the user returns home.

Obviously, Iā€™m far from being able to submit this app, but I feel like these steps, plus an additional M7 monitoring so Iā€™m not ranging all the time, combined with a strong enough pitch when I submit should get through. But I guess you never know.

Has anyone else tried this and had success/failure?

1 Like

This is great, thanks for sharing! :tada:

Just to see if I understand things right, is the goal to get more granular proximity data (than a binary inside/outside range, i.e. enter/exit) when youā€™re at home, to know where you are?

With Estimote Beacons, you can fine tune the broadcasting power (the minimum value = about 1-2 meters range), which could maybe make relying on enter/exits more of an option.

@heypiotr thatā€™s correct, my goal is to get granular proximity data so I can pop a notification as the user passes by the beacon.

In other updates, I have submitted my app and am just waiting on the review process to see if theyā€™ll allow it. Iā€™ll post here when I have a final answer.

1 Like

I can now say that Apple has approved my app that ranges beacons in the background using the aforementioned technique. So as long as you put some restrictions on it, it is allowed.

Ha, good to know! Did they have you explain why youā€™re using background ranging?

@heypiotr: I proactively explained both why I was using it and my algorithm for keeping it restricted.

Probably worth noting that although they accepted mine, the App Store is notorious for their inconsistency in what they accept and why. They could easily even reject future updates of my app. Especially since this technique relies on undocumented behavior, have no guarantees it will always work. But maybe the more apps in the Store that do this, the more likely they will make this a real feature someday.

2 Likes

@joefiorini, congrats!

We did similar solutions to yours and our app also did go through review successfully :smile: We also wrote quite detailed explanation why we use location updates and that we turn them on only when necessary.

Hello Sam,

Iā€™m currently developing an app with the same concern. Iā€™m thinking of starting the LocationManager on didEnterRegion and stopping it on Exit.

Can you let me know how you have progressed on this topic?

Best regards,

Morgan Zysman

startLocationUpdates can only be called in the foreground, so you canā€™t use it in didEnter when the app is in the background. Weā€™re not aware of any workaround to this, but maybe @Sam_G will have some idea?

Additionally, it looks like apps compiled against iOS 9 SDK (= Xcode 7) canā€™t range in the background at all anymoreā€”weā€™re still trying to confirm whether thatā€™s a bug, or a feature. Core Location documentation still states it should be possible. UPDATE: iOS 9 introduced a new property on the CLLocationManager, allowsBackgroundLocationUpdates, which needs to be set to YES/true for ranging in the background to work.

Hello thank you for your fast reply.
I have understood that when didEnter is being called we get 10 seconds of ā€˜foreground stateā€™ therefore iā€™m thinking of calling startLocationUpdates.

Can anyone confirm that?

Regards

On didEnter / didExit, the app is being woken up into the background for 10 seconds if itā€™s not running. Thinking in terms of the UIApplicationState enum, the app needs to be in the UIApplicationStateActive state in order for startLocationUpdates to work. When an app gets woken up into the background via didEnter / didExit, itā€™s in the UIApplicationStateBackground state instead.

UPDATE: just found a way to make starting and stopping location updates in the background work. If you startMonitoringSignificantLocationChanges in the foreground (you canā€™t start this one in the background), then startLocationUpdates will work in the background. (CC @Morgan_Zysman)

let beaconManager = ESTBeaconManager()
let locationManager = CLLocationManager()

override func viewDidLoad() {
    super.viewDidLoad()

    beaconManager.delegate = self
    beaconManager.requestAlwaysAuthorization()
    beaconManager.startMonitoringForRegion(beaconRegion)

    locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.startMonitoringSignificantLocationChanges()
}

func beaconManager(manager: AnyObject!, didEnterRegion region: CLBeaconRegion!) {
    print("didEnter")
    locationManager.startUpdatingLocation()
    beaconManager.startRangingBeaconsInRegion(beaconRegion)
}

func beaconManager(manager: AnyObject!, didExitRegion region: CLBeaconRegion!) {
    print("didExit")
    locationManager.stopUpdatingLocation()
    beaconManager.stopRangingBeaconsInRegion(beaconRegion)
}

func beaconManager(manager: AnyObject!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) {
    print("didRangeBeacons: \(beacons)")
}

Thank you very much for your answer, that is very similar to what I was thinking of doing.
Activate the locationManager on didEnterRegion.

I will try out your code right away.
I still have a question though, when location manager will trigger an update in background mode, will it call the didRangeBeacons from the beaconManager, or do I have to use the didRangeBeacons from the location manager?

Any ideas on how your code would pass the apple validation?

Regards,

Morgan

The location manager is there really only to keep the app running in the background. Ranging will work just fine from the ESTBeaconManager.

As for the app review, you need to demonstrate that your app provides value to the user in return for the background location updates capability. The most common acceptable use case is navigation. Iā€™d suggest leaving a note for the review team explaining how you use the background beacon ranging and whatā€™s in it for the user.