我正在用iBeacon测试杀死后在iOS应用程序中执行一些与任务相关的蓝牙。
事实上效果很好,但我仍然很好奇它是如何工作的。
这是我用过的一个代码。
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()
}
}
当应用程序最初启动时,我调用了startMonitoring()
一次,并使用了两个CLLocationManagerDelegate
方法。我还添加了log()
进行测试。
我预计在我杀死应用程序后,首先调用didEnterRegion
,然后调用didRange
,最后完成任务。
但事实证明,我只看到了3条关于";startMonitoring";,这意味着(我猜(iBeacon以某种方式调用了startMonitoring()
。
这怎么可能?为什么应用程序不调用委托方法,为什么它甚至运行良好?
在iOS上启动基于信标检测的应用程序效果良好,因为信标监控是建立在与地理围栏区域监控相同的CoreLocation框架功能之上的。它是这样工作的:
- 当你的应用程序注册了一个区域进行监控时,操作系统会记住你的应用和该区域,并将这两个区域添加到操作系统级别的跟踪列表中
- 每当iOS检测到位置变化时(CLCircularRegion监控的lat/lon或CLBeacon Region监测的BLE广告包(,它就会将变化与此跟踪列表进行比较
- 如果检测到状态发生变化,iOS会检查应用程序是否正在运行。如果是,它将根据需要调用didEnter或didExit委托方法
-
如果应用程序未运行,它会首先在后台启动应用程序,调用应用程序代理的didFinishLaunching方法
didFinishLaunching
返回后,iOS会检查触发启动的区域状态更改是否已在CoreLocation中注册。如果是,则调用didEnter或didExit
步骤4中的顺序对于实现这一点至关重要——如果您在应用程序代理中的didFinishLaunching
结束之前重新开始监控,则会得到didEnter回调
是的,即使在从任务切换器中杀死一个应用程序后,这一切都有效,因为iOS在杀死应用程序时不会删除应用程序的监控区域这是为数不多的在该操作后重新启动和应用程序的方法之一。
如果您没有看到与上述一致的日志行,则您的日志记录可能存在问题。尝试设置断点,您将看到按照我上面描述的顺序进行的调用。
有关CoreLocation更改启动应用程序时如何调用didFinishLaunching
的说明,请参阅本页。该页面专门用于重要的位置更改服务,但相同的机制也适用于信标监控:
如果您启动此服务,然后您的应用程序被终止,如果出现新事件,系统会自动在后台重新启动该应用程序。在这种情况下,传递给应用程序代理的application:willFinishLaunchingWithOptions:andapplication:didFinishLaunchngWithOptions:methods的选项字典包含键UIApplicationLaunchOptionsLocationKey,用于指示您的应用程序是由于位置事件而启动的。重新启动后,您仍然必须配置位置管理器对象并调用此方法才能继续接收位置事件。当您重新启动定位服务时,当前事件会立即传递给您的代理。此外,即使在启动定位服务之前,位置管理器对象的位置属性也会填充最新的位置对象。