There’s this one question we keep getting asked again and again from our customers: is it possible to locate a user while he’s not actively using our app? Let me rephrase that in a more generic way: is it possible to scan for iBeacons while the app is not actively used by the user? I recently had the pleasure to spend a few days on looking through API documentation, blog posts and pretty much the rest of the whole Internet in order to find a definitive answer to this question.
TLDR; for those who don’t want to see any of the technical stuff: yes, you can. BUT you have hardly any control over when you locate a user:
- everytime the user turns on the screen of his phone (it’s not required to actually unlock the device) you can scan for beacons and therefore locate the user.
- everytime the user is near (i.e. up to 20m) a beacon, you can react to that and scan again (the screen doesn’t have to be turned on for this to work!)
Diving deep into unkown water
Since I started developing for iOS, I have picked up quite some experience and I came to know one thing: there’s always a limitation on iOS. In the case of iBeacon and – more importantly – iBeacons in background it feels a bit like there’s more limitations than actual features. No, I’m kidding of course! iBeacon pushed indoo.rs and its technology a whole step further.
- – First things first, let’s clarify some basic terms:a “region” represents a specific configuration of iBeacons.
- – Regions match to UUID, major and minor of an iBeacon, but you can also define a region for all iBeacons matching only a UUID
- – “monitoring” is a very broad type of scan, where you only want to know if you’re “inside” a region or not
- – “ranging” is where you scan for individual beacons. This type of scan consumes a lot of power. It’s what is needed for reliably locating a user inside a room though.
Back to the limitations, let’s put them all in one place:
- – you can not reliably say when exactly you are able to scan for beacons
- – you can not scan for an indefinite amount of iBeacons
- – you can not scan for unknown iBeacons
- – nothing always works the way you expect it to
All but the first limitation listed here do not only apply to iBeacons in background, but for iBeacons on iOS in general. I decided to write about them here as well, just to make sure everyone’s on the same level.
“you can not reliably say when exactly you are able to scan for beacons”
iOS cares about your battery life, that’s why it tries to minimize the time spent scanning for iBeacons: as long as the screen is turned off, the device is in a power saving state and only scans for nearby beacons in an unknown cycle. In our case, this means that we might only get to know that we’re around one of our beacons when we already passed it and can’t see it anymore. So again, this means that we can not say “scan for beacons every X minutes”. We can only say “notify me when there is one of my beacons around” and then scan for beacons manually. If iOS decides to not tell you that you are near one of your beacons (for example because the signal is not reliable enough) you have no chance to scan for beacons.
In the worst case, you’ve already passed the beacon which triggered your scan. That’s because there’s a delay of up to 15 minutes! More information on delays can be found in Radius Networks’ excellent blog post.
“you can not scan for an indefinite amount of iBeacons”
This is actually one of the most pointless limitations I’ve ever heard of: there is a system-wide limit of 20 regions. Again, a region could be only one beacon, or a set of beacons. However, this limit also includes regions defined for your GPS location (geofencing)! Assuming a user has 15 reminders with a GPS region defined, you won’t be able to scan for iBeacons. No localization for you, my friend!
There is absolutely no technical reason for this limit. Apple’s reasoning is probably something like “we want to save your battery”, but I think that’s not a viable solution. Let’s hope for a change in iOS 8…
“you can not scan for unknown iBeacons”
Let’s keep this one short: you can’t scan for an iBeacon if you don’t know his UUID. Fullstop! No exceptions.
I think this whole topic is best explained by looking at the actual code we used for testing this.
Nothing special here. We start both monitoring and ranging and do not stop it when the app is closed. The ranging will pause, but the monitoring will continue when the user presses the home button. Killing your app or rebooting is no problem either.
One note about “region.notifyEntryStateOnDisplay”: if you set this to YES, your didEnter- / didExit-methods will always be called when the user turns on the screen (again, unlocking not necessary). I can’t think of a use case right now, but it’s good to know that it’s there…
The rest is self explanatory: everytime didEnter or didExit is called by the system, didRange will be called for the next 5-10 seconds too. Enough time for us to calculate a position and send it to some server if necessary. Or you could just pop up some fancy coupons for the user, because he’s standing right in front of the milk shelf? You decide.
“nothing always works the way you expect it to”
Just don’t be disappointed in case your coupon doesn’t pop up once…
working around the limitations
No limitation without a nasty workaround! Theoretically you could try to place your beacons so that the system thinks it enters and leaves a region again although your beacons are in the same building or even the same room by turning down the signal strength of the beacons. More specifically, between two beacons there should always be 5-10m where you can’t see any of the two beacons. This way the system should – theoretically – think that it enters a region (so you can scan for 5-10 seconds) and soon after leaves the region again (another 5-10 seconds scanning for you). 5-10m further the next beacon is in range, and you’ll be able to scan for 5-10 seconds again.
If you want to go down a completely different route, you could also replace your iBeacons with standard Bluetooth LE-beacons. In this case, there is a mode for apps to constantly scan for that. Possibility of getting denied from App Store review included though…
Found this useful, interesting or simply very entertaining? Then follow Tom’s blog and learn from the experience of a true Javaianer here.