iBeacon region monitoring AND proximity for >20 beacons?

UberJason picture UberJason · Aug 19, 2014 · Viewed 7.1k times · Source

I have been working on a prototype iOS app utilizing iBeacons to provide location-relevant information to office employees depending on where in the office they are. The ideal use case is that whenever an employee enters or exits their office, a callback is fired which provides them some information in the form of a notification (it might make a server query to get information first, etc - that sort of thing). We also want to be able to do this when the app is backgrounded or terminated; fortunately, we already know that beacon region boundary crossings trigger the appropriate CoreLocation callbacks even if the app is backgrounded or suspended.

From looking around, I understand that broadly, I have two options for how to approach the beacon region monitoring:

  1. Give each iBeacon its own CLBeaconRegion, and monitor for each of these regions independently.
  2. Monitor for CLBeaconRegions that correspond to multiple iBeacons - for example, each iBeacon has the same UUID and only monitor for a CLBeaconRegion corresponding to that UUID - then try to determine which beacon triggered the boundary crossing using ranging.

Thus far, I had chosen option #1. The advantage of this approach is that I get didEnterRegion: and didExitRegion: calls for each individual beacon and immediately know which beacon I have entered/exited. Also, I only get one enter call and one exit call, which is exactly what I want. Unfortunately, I just realized that this approach also limits me to 20 beacons (since each beacon gets its own region).

I'm not as familiar with the exact implementation details of #2, so correct me if I'm wrong. But it seems that this approach has more drawbacks:

  • Apple discourages ranging when the app is in the background because the results may not be as accurate.
  • The ranging calls fire once every second, while I only want to have "enter/exit" callbacks.
  • If the beacons have region overlap, the ranging calls might continually flip which one is "closest", which would further complicate things.

Basically, I'm wondering if there is a way to utilize option #2, but still have the benefits of option #1 - a quick and easy way to immediately determine which beacon triggered the region change with only one enter or exit callback?

I hope this question is clear enough. It's not all entirely clear in my own head, especially how ranging works.

Answer

davidgyoung picture davidgyoung · Aug 19, 2014

Option #2 is absolutely more complicated, but you must accept these complications in order to get around the 20 region monitoring limit.

A few points:

  • In the background, you only have around 5 seconds of ranging time, which does not give you as much time to average RSSI (signal strength) from each beacon to get a good distance estimate. So, yes, the estimates will be less accurate. If you understand this limitation and can live with it for your use case, there is nothing wrong with ranging in the background.

  • Yes, you will get multiple ranging calls per beacon after region entry, and you won't get any callbacks on region exit. You have to write extra code to take care of this. I have done this by maintaining a NSMutableArray of all the unique beacons (same uuid/major/minor) seen and update it in the ranging callback. You can then access this array in the region exit callback, so you know which beacons disappeared. Of course, it is possible that additional beacons were seen after the 5 seconds of background ranging time expires, but your app will never know about them. With this option, you must accept this limitation.

  • While it is true that errors on the distance estimate in ranging may incorrectly tell you which beacon is closest, you have an even worse problem when doing monitoring, because you don't get a distance estimate at all. If multiple beacons come into monitoring range around the same time, there is no guarantee that the first entered region callback you get will be for the closest beacon. So if your use case requires taking action based on the closest beacon, then you must do ranging (knowing that there may be error on the distance estimate.)