我正在使用 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 框架功能之上。它是这样工作的:
didFinishLaunching
返回后,iOS 检查触发启动的区域状态更改是否已向 CoreLocation 注册。如果是这样,它会调用 didEnter 或 didExit。第 4 步中的顺序对于完成这项工作至关重要——如果您在应用程序委托中
didFinishLaunching
结束之前重新开始监控,您将获得 didEnter 回调。
而且,是的,即使在从任务切换器中杀死应用程序后,这一切都有效,因为当应用程序被杀死时,iOS 不会删除应用程序的监控区域。 这是您可以在该操作后重新启动和应用程序的少数方法之一。
如果您没有看到与上述一致的日志行,则您的日志记录可能存在问题。尝试设置断点,您将看到按照我上面描述的顺序进行的调用。有关 Apple 对 CoreLocation 更改启动应用程序时如何调用
didFinishLaunching
的描述,请参阅此页面
。该页面专门用于重要的位置更改服务,但同样的机制适用于信标监控:
如果您启动此服务并且您的应用程序随后终止,则系统会在新事件到达时自动将应用程序重新启动到后台。在这种情况下,选项字典传递给 application:willFinishLaunchingWithOptions: 和 application:didFinishLaunchingWithOptions: 应用程序委托的方法包含键 UIApplicationLaunchOptionsLocationKey 以指示您的应用程序是由于位置事件而启动的。重新启动后,您仍必须配置位置管理器对象并调用此方法以继续接收位置事件。当您重新启动位置服务时,当前事件会立即传递给您的委托。此外,甚至在您开始位置服务之前,您的位置管理器对象的位置属性就会填充最新的位置对象。