iOS didEnterRegion有时不会被调用

时间:2017-08-02 11:28:04

标签: ios

我正在使用Swift2.3编写的项目上使用xcode 8.3.3。 我通过Cocoapods安装了SwiftLocation(2.3 Branch)库,以监控区域事件(didEnter / didExit Region)。

我有3/4区域同时平均监控 我按照以下方式添加它们:

do {
    let monitor = try Beacons.monitor(geographicRegion: epicenter, radius: 100, onStateDidChange: { (state) in
        state == .Entered ? self.delegate?.checkedIn(id, status: .Awake, onFinish: nil) : self.delegate?.checkedOut(id, status: .Awake, onFinish: nil)

   }) { (error) in
        let error = NSError(domain: “Monitor”, code: error._code, userInfo: [NSLocalizedDescriptionKey : error.description])
        self.delegate?.failedBecause(error)
    }

   monitor.onAuthorizationDidChange = { status in
        self.delegate?.movedTo(status)
    }

} catch let error {
    let error = NSError(domain: “Monitor”, code: error._code, userInfo: [NSLocalizedDescriptionKey : error as! AnyObject])
    self.delegate?.failedBecause(error)
}

我已经激活了背景模式并要求授权,我确信它在后台运行,因为应用程序已经醒来,即使应用程序被杀死,我也可以获取事件。 此外,设备上的gps和互联网连接都已打开。该功能似乎运行良好,但通常不会调用方法“Beacons.monitor(:)”的回调“onStateDidChange”。我有大量的退出事件真的很奇怪,但入口并不多。

我们已经测试过是否发生这种情况只是因为设备在添加监控时位于区域内但这似乎不是原因。怎么可能有时只有退出事件而不是入口?为了拦截退出事件,系统知道设备在区域内,但是没有触发入口事件。 任何有关解决此问题或调试它的帮助都非常感谢。

嗨@Gero。感谢您的回答。 您的情况很可能会发生。 我在XCode模拟器上模拟它要么直接杀死应用程序,要么在后台使用应用程序等待5分钟(因为Apple文档表明后台任务在3分钟后被杀死)。在这两种情况下UIApplicationLaunchOptionsLocationKey都不是空的,它告诉我应用程序已被唤醒。

在这种情况下,我执行一段代码,只是实例化LocationManager并将控制器设置为委托而不重新启动regionMonitoring。 我在服务器端有证据表明didEnter/didExit是通过此流程调用的。我知道这是因为应用程序进行HTTP调用以存储事件并发送“asleep”作为参数,以区别于它发送“清醒”的“标准”流程。

由于这个原因,我担心这不是原因,因为它仍然不清楚为什么它有时是有效的,有时不是。 我们将尝试使用requestState(for:)并告知您:wink:

1 个答案:

答案 0 :(得分:0)

好吧,这只是一个有根据的猜测,但由于评论太长,我会尝试将其变成一个答案。您的评论和(优秀)编辑向我表明您知道自己在做什么并采用正确的方法(旁注:关于该主题的许多问题都是由于对该功能的不正确理解造成的,所以起初我认为可能就是这样)。

我能想象的是这样: 当您在该区域之外时,该应用程序正在运行,即接下来的事情将是回调中的.Entered种状态。但是,在出现这种情况之前,应用程序会因为某些原因(内存?)而终止应用程序。

接下来,您进入该区域,以便重新启动该应用。您可以正确地计算出UIApplicationLaunchOptionsLocationKey字典中的launchOptions并再次启动您的区域监控。但是,我认为系统可能不会再通过回调显式传递状态更改。对于区域监测,文件并不清楚。所以现在你在这个区域内,但从未收到过状态变化回调。

解决方案是明确查询该区域,当且仅当您使用UIApplicationLaunchOptionsLocationKey使用requestState(for:) CLLocationManager和您所在地区({1}}重新启动您的应用时(如果这可能是单调乏味的话)你有多个地区,但可能是必需的。)

修改:对于它的价值,我偶然发现了dev forums上的相关问题,甚至在那里进一步澄清了这个问题。来自Apple工作人员的Gualtier Malde回答说,这应该是一个有效的来源。如果链接消失(有时似乎发生),这里是他解释的摘要和引用。

基本问题是关于重新启动(终止应用程序),然后应用程序没有获得区域更新。他的第一个答案是

  

重启后,在用户首先解锁设备之前,您的应用不会收到有关iBeacon事件的警报。没有办法解决这个问题。

     

如果您在用户解锁设备后遇到iBeacon检测问题,除非您的应用出现任何编码问题,首先要看的是iBeacon广告,并确保它是100%广告的规格,并且还根据其安装位置进行了正确校准。

然后我进一步询问简历即将发生的确切时间。我想知道是否因为这个原因,理论上可以错过区域更新,并且确切地说区域更新应该再次进入。回答:

  

是的,您的应用应该在后台重新启动 - 考虑到信标正确广告,蓝牙已开启等等 - 无需用户互动。

     

这一切只有在第一次解锁后才会发生。重新启动后,您的应用程序在第一次解锁后才会发生任何事情。   在第一次解锁之前发生的任何事件都可能被视为丢失给您的应用。

从此我认为,即使重新启动的应用程序也会获得区域更新。除非你主动重启设备,否则我不知道为什么你会错过任何一个。

有关您的测试程序的一点注意事项: 将应用程序置于后台并等待> 5分钟不会自动终止应用。它通常会简单地将其置于暂停状态。您提到的文档确实解释了后台任务在一定时间后终止(请注意,它们不保证在此确定时间,Apple在此处故意保持模糊以保持对未来更改和内容的控制),但并不意味着您的应用程序流程必然被杀死!任务刚刚结束,您的应用程序暂停。我们没有真正的方法让操作系统终止应用程序。如果AFAIK需要资源,它会这样做,但这很难以某种方式强制执行。此外,我也非常肯定在开发设备(特别是连接到Xcode /调试器)上的调试版本不一定像野外的iPhone一样。模拟器表现得更加不同。

所有这一切,我更加惊讶的是你得到application(_:didFinishLaunchingWithOptions:)电话,因为你描述你如何终止应用程序的方式甚至不应该导致它以常规,好的方式终止。也许你确实有一个错误,它崩溃(甚至被操作系统“惩罚 - 退出”?)等?我不知道一个应用程序是否试图“恶意地”购买后台处理(例如通过不诚实地回答application(_:performFetchWithCompletionHandler:)的完成处理程序或其他东西?)时间,系统可能会免除区域更新?可能就是这种情况,但我们超出了这个问题的范围。这一切都归结为应用程序状态问题,即生命周期问题。您必须非常小心地正确识别您正在尝试调试和期望进入的状态。