Connecting to multiple iBeacons at once - ios

If i have a device acting as a receiver and it connects to an iBeacon, what would happen if it connected to another iBeacon whilst still processing the connection to the first (e.g. Hadn't finished the running the didEnterRegion method)? Does the framework automatically handle this and create another sort of 'instance' or could I run into problems?
Thanks

I think that if they're all transmitting the same region (i.e. they all have the same proximity UUID) then CoreLocation won't keep sending the didEnterRegion and didExitRegion methods.
Once you start ranging for a region (that's a mouthful) the locationManager:didRangeBeacons:inRegion: method gets called repeatedly, which is where you can get the details of the connected beacons.

If CoreLocation detects two different region entry events in quick succession, it is certainly possible that two threads will execute your delegate's didEnterRegion simultaneously. So, yes, you could run into problems.
For this reason, you should be careful to:
Design your code in that method so that it will function properly if executed in simultaneous threads.
Design your code in that method so it exits quickly. Any long-running processing should be done in a new thread.
While the question mentions "connected to another iBeacon", it is important to understand there is no actual connection -- beacons are transmit only devices, and iOS will passively look for them and send delegate callback methods based on starting to see them, or no longer seeing them.

Related

Beacon monitoring in background iOS

I am developing an iOS app in Swift that monitors for beacon events. This is my first real beacon endeavor.
I am using Estimote beacons, but am not using the Estimote SDK. I am using core location and a CLLocationManager with didExit and didEnter events.
I am only listening for beacons that are registered with the current user that is signed in to my app. For example, John Doe could be registered with beacons A and B, while Mary Sue is only registered to beacon C. I am experiencing a lot of false leaves, and wonder if it is because of where I am implementing my code.
I understand that there is a default 30 second latency when validating a leave event, but I am experiencing periods of longer than 30 seconds without a bluetooth signal from point blank range. Perhaps implement a 30 minute window rather than 30 seconds for a leave validation?
Since a user has to sign-in in order to know what beacons to monitor, the location manager resides within the user's default profile view controller. I successfully get beacon interaction even when the phone is locked, but it is not consistent. I am concerned because I know that the view controller itself is suspended/activated at the iPhone's discretion and may be revealing flaws in my logic.
Should all location oriented code be placed within the app delegate file? If I implement a protocol from my profile view to the app delegate, I can instantiate it there within the app delegate first and then retrieve the beacon data later, once the user is signed in.
I have struggled to find an "iOS beacon convention" in my research, just examples that provide some results. Not too sure whats actually considered proper practice.
Thanks!
It is common to use a software filter to ignore spurious region exit events if an entry event happens soon afterward.
To make this independent of any one ViewController, it is important to have the logic triggered by the AppDelegate. Two choices here:
Put region monitoring callbacks and filter logic directly in the AppDelegate. This is appropriate for small and simple apps.
Put callbacks and filter logic in a custom class, and initialize it from the AppDelegate's didFinishLaunching method. This is the best approach for larger and more complex apps to keep the AppDelegate simple and clean.
Either way, it is critical to trigger starting of monitoring from the didFinishLaunching method. This ensures proper background CoreLocation setup should your app be auto launched by region transitions.

Refresh iBeacon state

I am newbie with iBeacon and need some help. Already found some useful info from other topics but still searching for answers.
Is there a way to receive notification about my state at position right after app is killed or after I switch ON bluetooth? Now I got notifications only after state changes.
Example: I need to have notification when I got to point 'A'. But I got there and realized that my bluetooth is OFF. I switched bluetooth ON and didn't get anything because iBeacon thought I am 'INSIDE' from beginning. This happens when app is not foreground (but not 100% times, sometimes iBeacon 'rescan' and send his state again).
I need to somehow manually refresh iBeacon state and get methods didDetermineState or didRangeBeacons to work. I tried to stop and start monitoring after app is killed to forces the notification, but doesn't seem it works. I know there is a way to get this 'refresh' after turning ON display, but it could be perfect to also get it in other situations when needed.
Lots of location and beacon events can wake up an app that is running in the background, but relatively few events are sent to apps that have been killed via the task switcher or were never launched since boot.
The only bluetooth events capable of launching a non running app are:
didEnterRegion (for CLBeaconRegions)
didExitRegion (for CLBeaconRegions)
Other events received only by foreground/background running apps:
didDetermineStateForRegion
CoreBluetooth device discovery
CoreBluetooth power state changes
The last one is the event you care about, but it just won't be sent to apps that are not running. One alternative may be to rely on other location events like Significant Location Change, which launches a non-running app when the user moves "significantly" (e.g. to the next cell tower). You could register for these events and check Bluetooth state at that time. This may be the best you can do.

HTTP request in case of didEnterRegion, didExitRegion

I am a little bit confused about this question.
Somewhere I read, it is not allowed by Apple to make network requests, when an app not in the foreground. Is also the case, when app is woken up by locationManager events?
What I'd like to: define a Beacon region, handle locationManager:didEnterRegion: and locationManager:didExitRegion: to call my simple web service methods. It should be done even if the app is not active and woken up by location manager.
Technically it is easy to implement - basically, I have already made it - but I don't know if it is allowed by Apple, and would take app review successfully.
Thanks!
Yes, it is allowed. It is a common technique, and I have several apps in the AppStore that do this. The Beacon Scavenger Hunt, for example, sends stats back to our server when participants use the iOS app to find beacon targets in the hunt.
When you detect a beacon in the background, however, you only have about 5 seconds of running time from iOS. Take care that your server responds quickly enough. This small time window is the way Apple enforces that people don't abuse this.

How can I tell if CLLocationManager is actively scanning for a beacon?

When you set up an iOS device as a beacon (peripheral role), you can query its state by calling CBPeripheralManager.isAdvertising. I can't find the equivalent to query whether a device is scanning for a beacon (central role) on CLLocationManager. Any ideas?
Update:
Given David's answer, I encapsulated the code setting up the CLBeaconRegion with the specific UUID and added a boolean variable which is changed when calling startMonitoringRegion and stopMonitoringRegion on CLLocationManager.
I do not believe there is any way this is possible. Even though CoreLocation's iBeacon APIs use Bluetooth LE and CoreBluetooth under the hood, Apple appears to have gone to some lengths to hide this implementation. There is no obvious way to see whether a Bluetooth LE scan is going on at a specific point in time.
Generally speaking, a Bluetooth LE scan is always going on when an app is ranging for iBeacons in the foreground. When an app is monitoring for iBeacons (either in the foreground or background) or ranging in the background, indirect evidence suggests that scans for beacons take place every few minutes, with the exact number ranging from 1-15 depending on phone model and state. I know of no way to programmatically detect the exact times when this starts and stops, although it can be inferred by iBeacon monitoring entry/exit times. If you look at the graph below, the blue dots show the inferred scan times for one particular test case. Details of how I inferred this are described in this blog post.

How to Handle the iBeacons overlapping eachother

I have created a app for detecting the beacons. things are going on good. the problem that I have is:
When there are more beacons overlapping on one another. how am I suppose to handle the situation considering the case
1. When we want to receive the offer only once from a particular beacon on entering to the beacon/we are in the place where we have more than one beacon overlapping each other.
Thanks,
When you have overlapping iBeacons, it is important to design the iBeacon identifiers (UUID, major, minor) and the CLBeaconRegions you use to monitor them so that you get the results you want.
Do you want to trigger "the offer" whenever any of the overlapping iBeacons are detected? If so, then monitor for a CLBeaconRegion that matches them all, probably by setting just the UUID (and maybe the major if all beacons share that value.) In this case, you will only get one Region entry notification when any of them are detected. You won't get one for each overlapping iBeacon.
If you only want to trigger "the offer" when a single one of the overlapping iBeacons is detected, then monitor for a CLBeaconRegion that only matches that one iBeacon, typically by specifying the UUID, major, and minor in that CLBeaconRegion. Of course, you also need to ensure that each iBeacon is configured with a different minor. Remember, too, that you can monitor for multiple CLBeaconRegions simultaneously, if needed, and get a specific callback for each one.
While it a separate issue from overlapping iBeacons, if you really want users to "receive the offer only once", you also need to add a filter to your detection callback. A glitch in iOS sometimes gives you a very quick exited region callback followed by an almost instantaneous entered region callback. In order to prevent users from getting the offer a second time, store off the timestamp of the last time the offer was pushed to the user, and only push it again if enough time has passed (say 1 hour or one day.) See this answer for details.
My workflow at the moment is to detect in the didRangeBeacons method the Beacon which is the closest to my actual position. This is done by comparing for each beacon the rssi property.
After identifying the closest Beacon I process the desired action for this beacon.
To avoid that this action is triggered repeatedly (beacause the didRangeBeacons method is triggered a couple of times per seconds) I implemented an isLocked Flag (BOOL) in my actual beaconHandler, which does the processing.
So I only react to the Beacon which is the closest to me. And I only react once. I also keep track of my last beacon which I identified as closest. This enables me to react immediatly, If you are getting in Range of another beacon. So e.g. when you walk along a store, every beacon is triggered immediatly, but not repeatedly.

Resources