2
votes

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?

1
Hey, did you manage to somehow solve this? Have the same problem, when app is manually killed and then turn on bluetooth.JInn

1 Answers

3
votes

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.)