2

Still fighting with iBeacon monitoring for screen-off mode in my iOS app.

In my experiment, when the screen is turned off, the delegate method "locationManager:didRangeBeacons:inRegion:" is still triggered continuously, but, as soon as the screen is off, the signal disappears accordingly(RSSI=0, beacon.accuracy=-1.0), and then, 10 seconds later, there is no beacon found at all.

I found some important information in this post saying that "iOS uses beacons in two different ways: region monitoring and beacon ranging. The latter does NOT work in the background ..., or when the app is terminated.

CLLocationManager will ONLY fire off ONE delegate call when a region is entered. If you start monitoring for a region while inside of that said region, the entry delegate will NOT be called. Your app will have to manually call the CLLocationManager’s requestStateForRegion method. Once you’ve exited the monitored region(s), CLLocationManager will call the didExitRegion approximately 30-45 seconds later."

Now I tried to call the "requestStateForRegion:" method continuously when the screen is off. The result is:

  1. If my iPhone is already in the iBeacon region, the delegate method "didDetermineState" gives "CLRegionStateInside" continuously;
  2. When I hold my iPhone and walk outside the iBeacon region, or just shut down the iBeacon's advertising, after 30-45 seconds, the delegate method "didDetermineState" turns to "CLRegionStateOutside" and keeps in "outside" state;
  3. When I hold my iPhone and walk inside the iBeacon region, or turn on the iBeacon's advertising again, the delegate method "didDetermineState" still gives "outside" continuously and NEVER TURNS BACK TO "inside".

What I need is, when the screen is off, I can detect as soon as my iOS device enters the iBeacon region. Asking for help...Thanks in advance.

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
kuang
  • 309
  • 1
  • 11

2 Answers2

2

Have you added the NSLocationAlwaysUsageDescription in your info.plist? I can really recommend you to follow this tutorial which goes through all this.

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
0

When you start monitoring, there's always an initial call to the didDetermineState delegate. This is how you can figure out if you're already in the beacon region. From then on, you can continue relying on didEnter/didExit (didDetermineState is also called alongside these). The only catch is, if the user turns Bluetooth off and then back on again—you will lose any state transitions that ordinarily would've happened during that time—so it's a good idea to call requestState after you detect Bluetooth is back on, to get caught up on the current state.

All in all, there's no need to call requestState continuously, and you can't ordinarily even do so when the screen is locked—iOS will put your app to sleep, per my answer to your other question. Unless you're using Background Modes to keep the app running in the background, but then you must be able to defend it when you submit your app for review, as Background Modes are reserved for very specific use cases. You should rely on automatic calls to didEnter/didExit/didDetermineState, aided by requestState if Bluetooth is turned off and on.

When I hold my iPhone and walk inside the iBeacon region, or turn on the iBeacon's advertising again, the delegate method "didDetermineState" still gives "outside" continuously and NEVER TURNS BACK TO "inside".

Keep in mind that depending on hardware capabilities of your iOS device (you haven't mentioned which one you're testing with), the "enter" event might take a while to trigger. The guys at Radius did some testing long time ago, and it was up to 15 minutes for iPhone 4S on iOS 7.1. That's b/c iPhone 4S doesn't support offloading BLE scanning to the Bluetooth chip, unlike newer iPhone models. But even on these newer models, there's a limit of how many scans can be offloaded to the chip, which Radius also measured to be 30 (on iOS 8.3 and with 3 different iOS devices).

Community
  • 1
  • 1
heypiotr
  • 2,139
  • 2
  • 15
  • 22
  • Thank you so much. My device is iPhone 5s. Now I removed the continuous "requestState" and turned to catch the "didEnter"/"didExit" delegate methods. The result is all the same, in screen-off mode, "didExit" can be caught but "didEnter" is never triggered, while the latter is what I really need. (Suppose most of the use case is that the iPhone is in user's pocket with screen off, and when approaching an iBeacon, a push notification should be kindled, which relies on "didEnter" being caught in time.) – kuang Dec 29 '15 at 03:24