【问题标题】:(iOS) How does waking up by iBeacon work?(iOS) 通过 iBeacon 唤醒是如何工作的?
【发布时间】:2021-12-29 21:56:51
【问题描述】:

我正在使用 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 swift core-location core-bluetooth ibeacon


    【解决方案1】:

    基于信标检测启动应用程序在 iOS 上运行良好,因为信标监控建立在与地理围栏区域监控相同的 CoreLocation 框架功能之上。它的工作原理是这样的:

    1. 当您的应用注册一个区域进行监控时,操作系统会记住您的应用和该区域,并将这对添加到操作系统级别的跟踪列表中。
    2. 每当 iOS 检测到位置变化(用于 CLCircularRegion 监控的纬度/经度或用于 CLBeaconRegion 监控的 BLE 广告数据包)时,它都会将更改与此跟踪列表进行比较。
    3. 如果检测到状态变化,iOS 会检查应用程序是否正在运行。如果是这样,它会酌情调用 didEnter 或 didExit 委托方法。
    4. 如果应用没有运行,它首先将应用启动到后台,调用应用代理的 onCreate 方法。 didFinishLaunching 返回后,iOS 会检查触发启动的区域状态更改是否已向 CoreLocation 注册。如果是,它会调用 didEnter 或 didExit。

    步骤 4 中的顺序对于完成这项工作至关重要 - 如果您在应用委托中的 didFinishLaunching 结束之前重新开始监控,您会收到 didEnter 回调。

    而且,是的,即使在从任务切换器中终止应用后,这一切仍然有效,因为 iOS 不会在应用终止时删除应用的受监控区域。这是您可以做到的少数几种方法之一在该操作后重新启动和应用。

    如果您没有看到与上述一致的日志行,则您的日志记录可能存在问题。尝试设置断点,您将看到按照我上面描述的顺序进行的调用。

    请参阅this page,了解 Apple 关于在 CoreLocation 更改启动应用程序时如何调用 didFinishLaunching 的说明。该页面专门针对重大位置更改服务,但同样的机制也适用于信标监控:

    如果您启动此服务并且您的应用随后被终止,则系统会在新事件到达时自动将应用重新启动到后台。在这种情况下,传递给 application:willFinishLaunchingWithOptions: 和 application:didFinishLaunchingWithOptions: 应用程序委托方法的选项字典包含键 UIApplicationLaunchOptionsLocationKey 以指示您的应用程序是由于位置事件而启动的。重新启动后,您仍必须配置位置管理器对象并调用此方法以继续接收位置事件。当您重新启动位置服务时,当前事件会立即传递给您的委托。此外,即使在您启动位置服务之前,您的位置管理器对象的位置属性也会填充最新的位置对象。

    【讨论】:

    • 感谢您的回复。这是一个小问题。你能给我一个关于onCreate方法的链接吗?官方文档上没找到。
    • 还有一个问题。似乎我想要的任务(相关蓝牙)也适用于startMonitoring(for:)(没有startRangingBeacons())。是不是因为startMonitoring(for:)唤醒了应用才发生的?
    • 查看我编辑的答案,底部有指向 Apple 文档的链接。 (当我说 onCreate 时我说错了——我应该说 didFinishLaunching——我已经在我的编辑中纠正了这一点。)而且,是的,不管你是否调用 startRangingBeacons 对后台启动没有影响——它是 startMonitoring键。
    • 最后我只使用startMonitoring(for:)。但我还是有点困惑。当我关闭 iBeacon(这意味着调用 didExit)时,我预计我的应用程序仍将在 BG 上,但似乎很快就会被杀死。这是正确的场景吗?
    • 通常,当您将应用程序置于后台时,它会以挂起状态停留在内存中,并且不需要在 didEnter/didExit 上重新启动。应用程序可以保持这种状态数小时甚至数天。但是,iOS 可能会随时终止应用程序并将其从内存中删除。它通常在内存不足时这样做,可能是因为您正在使用另一个需要大量内存的应用程序,如游戏、地图等。很难判断这是否发生。如果您在 didExit 或 didEnter 之前第一次收到对 didFinishLaunching 的调用,您就会知道应用程序是否已被终止并重新启动
    猜你喜欢
    • 2018-01-16
    • 2022-01-17
    • 2016-07-29
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 2018-01-12
    相关资源
    最近更新 更多