【问题标题】:CLLocationManager Region Monitoring: Detect Arrival in Suspended StateCLLocationManager 区域监控:检测到达暂停状态
【发布时间】:2018-03-05 23:56:43
【问题描述】:

我正在寻找一种方法来跟踪用户是否已到达指定的一组坐标附近。该功能需要在应用程序在后台运行时(最好在 100 米内)。此外,为了节省电池电量,理想情况下我不希望获得太多坐标读数(可能每 10 分钟读数一次,持续时间不超过几个小时)。

我尝试了几种方法来完成这项任务,但都无法获得预期的结果:

后台计时器:

我在 (App.delegate) 中添加了一个后台任务

func applicationDidEnterBackground(_ application: UIApplication)

其中执行了一个重复的Timer.scheduledTimer来获取坐标并处理

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])

检测用户是否在范围内。如果在短期内应用这种方法,但只能在应用程序暂停之前,大约 3 分钟。理想情况下,我不希望如此频繁地获取坐标。

区域监控:

我已经初始化了 CLLocationManager,如下所示:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    locationManager.delegate = self
    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.pausesLocationUpdatesAutomatically = false
    locationManager.activityType = .otherNavigation
    locationManager.requestAlwaysAuthorization()
}

LocationManager 在应用程序进入后台时启动:

func applicationDidEnterBackground(_ application: UIApplication) {
    self.monitorRegionAtLocation(center: CLLocationCoordinate2D(latitude: x, longitude: y), identifier: id)
    locationManager.startUpdatingLocation()
}

区域监控代码:

func monitorRegionAtLocation(center: CLLocationCoordinate2D, identifier: String ) {
    // Make sure the app is authorized.
    if CLLocationManager.authorizationStatus() == .authorizedAlways {
        // Make sure region monitoring is supported.
        if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
            // Register the region.
            let maxDistance = 200.0
            let region = CLCircularRegion(center: center,
                                          radius: maxDistance, identifier: identifier)
            region.notifyOnEntry = true
            region.notifyOnExit = false

            locationManager.startMonitoring(for: region)
        }
    }
}

我为 CLLocationManager 添加了一个 didEnterRegion 功能块:

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    if let region = region as? CLCircularRegion {
        let identifier = region.identifier
        print("FOUND: " + identifier)
    }
}

该代码似乎可用于检测进入某个区域,但是在后台时坐标不会更新。

其他信息

  • 我启用了位置更新和后台获取的后台模式
  • 我在 Info.plist 中提供了“位置始终使用说明”和“位置使用时使用说明”的值
  • 应用设置显示针对位置的“始终”权限

我相信必须有更好的方法在后台进行此类检查,但我还没有发现任何检测后台其他动作的方法。

我们将不胜感激任何关于此事的指导,如果您需要更多信息,请告诉我,我会尽我所能。

更新:

我已按照以下 cmets 的建议修改了方法以使用区域监控。

【问题讨论】:

  • 谢谢@Paulw11。我已经修改了方法和问题以更好地适应区域监控,但是我无法从后台获取坐标。
  • 你在哪里初始化你的locationManager?是局部变量还是类属性?
  • 您想在被杀死或暂停模式下获取坐标吗?我最近完成了一个关于地理围栏的项目,发现它只有在应用程序处于后台时才有效,明天我会用我所做的事情更新你。如果我对你有帮助会很高兴。 :)
  • @TarasChernyshenko 我目前在 AppDelegate 中对其进行了初始化。最初设计 Background Timer 解决方案时,我将其包含在一个单独的 BackgroundWorker 类中,该类似乎可以工作,直到应用程序在 3 分钟后暂停。

标签: ios swift background cllocationmanager geofencing


【解决方案1】:

任何位置更新/监控都需要正确配置其位置管理器,以便它可以发挥最佳作用,提供所需的位置更新。在进行后台位置更新时检查一些要点很重要:

1.检查位置更新的后台模式和后台获取应该启用

2.应在 Info.plist 中勾选“Location Always Usage Description”和“Location When in Use Usage Description”

3.检查您是否要在位置更新之间暂停 - 如果是,那么您需要提供活动类型,以便位置管理员可以确定为您暂停位置更新的最佳方式

4.检查您是否要应用距离过滤器 - 您希望用户(设备)移动一些最小量,以便位置管理器发送更新的位置

5.检查您是否想要所需的精度 - 这可能会导致某些精度类型的功耗

在您的代码中,我可以看到位置管理器配置了一些参数,但缺少背景模式的精度和距离过滤器。

   locationManager.allowsBackgroundLocationUpdates = true
   locationManager.pausesLocationUpdatesAutomatically = false
   locationManager.activityType = .otherNavigation

此外,如果您在 Apple doc 中看到暂停位置更新属性,它会显示:

对于具有使用中授权的应用,暂停位置更新 结束对位置更改的访问,直到应用再次启动并且 能够重新启动这些更新。如果您不希望位置更新 完全停止,考虑禁用此属性并更改位置 当您的应用移动到时,精度为 kCLLocationAccuracyThreeKilometers 背景。这样做可以让您继续接收位置 以省电的方式更新。

本质上,它告诉如果你想禁用暂停,那么你必须保持精度水平(kCLLocationAccuracyThreeKilometers)。我猜您的方法中缺少这一点。

另外,您可以查看this link,它实际上启动了后台任务,然后在后台任务中启动了位置管理器监控。 希望对您有所帮助。

【讨论】:

  • 感谢您的反馈。周末我用区域监控运行了一些测试,并且能够从后台建立一些 didEnterRegion 触发器。我不相信在使用 locationManager.startMonitoringSignificantLocationChanges() 时需要精度或距离过滤器,我最终选择使用它。 This resource 是深入了解我的问题的非常有用的指南,但您的观点也很重要。
  • 好的。伟大的。那么真正的问题是什么?
【解决方案2】:

问题是“CLLocationManager 区域监控:在后台检测到达”。这很有可能,但是在被杀死后检测到任何东西是不可能的(从 iOS 7 开始)。

每当用户向上滑动您的应用程序切换器时,iOS 都会接受它,因为用户不希望应用程序在后台运行,因此所有回调都会停止。

This answerthis answerthis answer 也说了同样的话。不过Apple doc 有点混乱。

我个人的观察是,即使在 Killed 模式下也会调用应用程序,但很少。

关于获取位置,每当调用地理围栏的委托方法时,您都可以轻松获取位置。

您的要求确实不需要后台模式。

不幸的是(幸运的是 iOS 用户,因为他们节省了电池电量)我们真的没有办法在应用程序被杀死后 1 小时内获取位置。

【讨论】:

  • 感谢您的评论。也许我在陈述“背景”时混淆了这个问题,但我的意思是处于暂停状态(我已经在标题中修复了这个问题)。似乎该解决方案将工作大约 3 分钟,这可能是后台状态,但之后停止运行,我怀疑这是由于应用程序进入挂起状态。该应用程序仍在 App-Switcher 中,并没有被向上滑动以杀死它(只是坐在后台)。
猜你喜欢
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 2012-06-11
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
相关资源
最近更新 更多