I'm experiencing a strange problem with iBeacon monitoring in iOS.
The test I'm running is,
1.Start monitoring for beacon region.
2.Wait a few seconds and then turn on the beacon.
3.didEnterRegion is called and I call startRangingBeacons.
4.I start receiving regular callbacks through didRangeBeacons.
5.I turn the beacon off, and continue to get didRangeBeacon callbacks for a second or two.
6.Then I receive didExitRegion.
7.Now the weird bit, I then get one further call to didRangeBeacons.
If I turn the beacon back on after this then didEnterRegion is not called, despite the fact that didExitRegion was called. It seems like the rougue call to didRangeBeacons means iOS now thinks the beacon is in range again.
Is this the behaviour people would expect? Or does this indicate a problem with my code?
EDIT:
I'm seeing this behaviour on an iPhone 4 running 7.0.6, if i run the same test with a 5C running 7.1 and a 5S running 7.1.1 everything is fine.
I wouldn't expect that behaviour either. However, in the discussion of didRangeBeacons:inRegion: it says:
The location manager calls this method whenever a beacon comes within range or goes out of range
This could be the explanation of the behaviour you are referring to in bullet 7.
It is not mentioned, however, whether this goes out of range call is performed before or after the monitor delegate calls. Similarly, this does not explain why you are no longer receiving didEnterRegion: calls.
Related
Sometimes app didn't execute the didExitRegion event in the following cases.
Bluetooth OFF
Keep device/beacon away
Switched OFF the Beacon
After the missed didExit event, didEnter even also won't execute because the iOS(OS/App) thinks beacon still exists. It happens until restart the power cycle of the beacon.
I have tried to overcome this issue programmatically. But it seems like I didn't fix it.
I have tried the following steps to overcome this issue
Based on the ranging/didDetermine status I have executed didExit event manually. (It didn't help)
I've tried with restart the beacon monitoring (It didn't help)
Aspected Result: didEnter/didExit events must be worked when the beacon is coming to the range or exiting from the range.
Can iOS receive iBeacon packet in sleep state and wake up the app?
I killed an app and restarted, then kept the phone in sleep mode. The device was was in beacon region when device reboot and I kept the device screen off after reboot.
My iOS app is not waking, so I suspect its not receiving iBeacon packet.
I checked the system log and found that the didEnterRegion procedure is not getting called.
Does app wakeup works incase of force terminated app and does iOS receive iBeacon packet in reboot and immediate sleep state?
If I make screen on then it starts working immediately but if screen is off after reboot its not receiving iBeacon packet.
Yes, iOS CoreLocation will launch your app on region entry or region exit, and works even after force termination after iOS 7.1.1. You will only get the appropriate callback if you set up your CLLocationManagerDelegate in the AppDelegate's didFinishLaunchingWithOptions method. If you do not set this up in that method, then CoreLocation will not know to make the callback after app launch.
Testing entry events across an app restart can be a little tricky, so here are a few tips to avoid pitfalls:
If is critical that your app think that it is "outside" the region when it was last running. If it was "inside" the region when it was last running, it won't necessarily get another entry callback because it will think it never left. When testing, make absolutely sure you get a didExit callback or a didDetermineState callback that says it is out of region before you kill the app or reboot. Verify this with a NSLog statement, a local notification, or some custom UI indicator added to a screen of your app.
If you reboot an iOS device, CoreLocation is not fully initialized right away -- I have seen it take 5 minutes after the screen comes on before I get any callbacks. Be sure you wait long enough.
Once CoreLocation is fully initialized, region entry events typically happen within one second of when the beacon comes into range. However, if the limited bluetooth hardware assist pattern slots are all full on the device (typically this happens if you have a few other beacon apps that have used them all), then entry events fall back to software scans that happen only every 10 minutes or more. An entry event can take that long in such a situation. Make sure you wait long enough before assuming it isn't working.
I am testing iBeacon region monitoring and doing the following steps.
1: Precondition: Bluetooth is on in the phone and App is not running
2: I turn the beacon on
3: The app gets launched following a location event (beacon region)
4: I turned the beacon off
5: The app is still running and detects the did exit region event
6: I then kill the app manually (it is ok to do so, region monitoring will still work)
7: I turn off Bluetooth on the phone
8: I turn the beacon back on
9: I turn on Bluetooth again on the phone
10: I expect to... see below (Expected result)
Expected result: the app should wake up following entering the region (I tested this without manually switching the Bluetooth and it works)
Actual result: does not happen.
Why does 10 not happen? Is this a bug in iOS?
Turning Bluetooth off doesn't usually work as a good way to test monitoring. Enter and exit events only happen when the region's state (i.e., CLRegionState) transitions from "outside" to "inside" (and vice versa). If you turn Bluetooth off, the state goes to "unknown"[1] (because how would the device know if you're out or in with Bluetooth disabled), and thus if you switch it back on, and it transitions to "outside" or "inside," it won't actually trigger an event by design.
You can test that by implementing the didDetermineState method, in addition to didEnter and didExit. Start with the beacon turned off, confirm via didDetermineState that the state is "outside." Turn Bluetooth off, turn the beacon on, turn Bluetooth on. You will see didDetermineState with state "inside," but no didEnter. (It works the same the other way around, i.e., if you start with the beacon turned on, and turn it off while the iPhone's Bluetooth is disabled. You will see didDetermineState "outside," but no didExit.)
Note: this test only works in the foreground. It looks like in the background, didDetermineState is not enough for iOS to wake up the app to handle the event—it needs to be didEnter or didExit.
[1] A little clarification here as well. When you disable Bluetooth, there won't actually be an explicit call to didDetermineState with CLRegionStateUnknown. This is because I suspect that iOS stops delivering any beacon events when Bluetooth is off. How did I arrive at the conclusion that it really changes to "unknown" then? I added an NSTimer that calls requestStateForRegion (which in turn forces an asynchronous call to didDetermineState) every second. When I turn Bluetooth off, didDetermineState calls stop arriving. But as soon as I turn Bluetooth on, these calls resume, and the state is "unknown"—before it changes to "outside" or "inside" depending on the current state of the beacon. Again, per the note above, all of this is with the app in the foreground.
(Same mechanics actually apply when you start monitoring already in range of a beacon. Before you start monitoring, the state is "unknown." When you start monitoring, the state transitions to "inside" our "outside" (depending on whether the beacon is in range at the time when monitoring starts), but this does not trigger didEnter or didExit. Here too you can verify this with didDetermineState.)
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.
I'm working with a sample app for iBeacon region monitoring functionality. The Issue(not sure if it is) that I was unable to resolve is "didEnterRegion:" fires continuously for more than 2 times when I enter the region. This happens to send the local notification more than once or the times that this method fires when the app is in minimized mode.
Can anybody tell me how to resolve this.
Thanks,
It is common for a glitch in iOS to cause a didExitRegion event followed within a second by a didEnterRegion event. You can filter these out in your code by storing in an NSDate variable the time you last exited the region. When you get a didEnterRegion callback, you simply ignore it if the exit timestamp was within the last few secs.
If you are really getting these continuously as you say, something else is wrong that you may need to fix. It is possible that your iBeacon is not transmitting at least once every three seconds. This would cause constant exit/entry callbacks.