Home > Blockchain >  (iOS) How does waking up by iBeacon work?
(iOS) How does waking up by iBeacon work?

Time:11-20

I'm testing with iBeacon for doing some task related Bluetooth in a iOS app after killed.

Actually It works out very well, but I'm still curious how it works.

Here is a code that I used.

private func startMonitoring() {
    if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
        self.log("startMonitoring")
        let region = CLBeaconRegion(...)
        self.locationManager.startMonitoring(for: region)
    }
}

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    if let region = region as? CLBeaconRegion {
        if CLLocationManager.isRangingAvailable() {
            self.log("didEnterRegion")
            self.locationManager.startRangingBeacons(satisfying: region.beaconIdentityConstraint)
        }
    }
}

func locationManager(_ manager: CLLocationManager, didRange beacons: [CLBeacon], satisfying beaconConstraint: CLBeaconIdentityConstraint) {
    if !beacons.isEmpty {
        self.log("didRange")
        self.doSomething()
    }
}

I called startMonitoring() once when app is initially started and used two CLLocationManagerDelegate methods. And also I added log() for test.

I expected after I kill the app, didEnterRegion is called first and then didRange is called and finally do the task.

But it turns out, I just see 3 logs about "startMonitoring", which means (I guess) iBeacon called startMonitoring() somehow.

How is it possible? Why doesn't the app call delegate methods, and why does it even works out well?

CodePudding user response:

Launching an app based on beacon detection works well on iOS because beacon monitoring is built on top of the same CoreLocation framework functionality as geofence region monitoring. It works like this:

  1. When your app registers a Region for monitoring, the operating system remembers your app and the region, adding this pair to an OS-level tracking list.
  2. Whenever iOS senses a location change (lat/lon for CLCircularRegion monitoring or BLE advert packets for CLBeaconRegion monitoring), it compares the change against this tracking list.
  3. If a change in state is detected, iOS checks if the app is running. If so, it calls the didEnter or didExit delegate methods as appropriate.
  4. If the app is not running, it first launches the app into the background, calling the app delegate’s onCreate method. After didFinishLaunching returns, iOS checks if the region state change that triggered the launch is registered with CoreLocation. If so, it calls didEnter or didExit.

The sequence in step 4 is critical for making this work — if you re-start monitoring before the end of didFinishLaunching in your app delegate, you get the didEnter callback.

And, yes, this all works even after killing an app from the task switcher because iOS does not remove an app’s monitored regions when the app is killed. It is one of the few ways you can relaunch and app after that action.

If you are not seeing log lines consistent with the above, there may be an issue with your logging. Try setting breakpoints and you will see the calls made in the sequence I describe above.

See this page for Apple's description of how didFinishLaunching is called when a CoreLocation change launches the app. That page is specifically for the significant location change service, but the same mechanism applies to beacon monitoring.

  • Related