持续位置更新后台iOS13

12

我目前正在测试iOS 13的后台位置模式,因为我想要在后台跟踪用户的位置和运动(使用CMMotionManager)。 因此,我有自己的(singleton)类处理位置跟踪。我以以下方式初始化CLLocationManager:

    func initializeLocationManager() -> CLLocationManager {
        let manager = locationManager ?? CLLocationManager()
        manager.delegate = self
        manager.requestAlwaysAuthorization()
        manager.allowsBackgroundLocationUpdates = true
        manager.pausesLocationUpdatesAutomatically = false
        manager.distanceFilter = kCLDistanceFilterNone
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.activityType = .other
        return manager
    }

然后我启动以下服务:

   func startLocationServices() {
        // ...
        locationManager.startUpdatingLocation()
        locationManager.startMonitoringVisits()
        locationManager.startMonitoringSignificantLocationChanges()
        // ...
    }

此外,我实现了CLLocationManagerDelegate方法didChangeAuthorization()和didUpdateLocation()。

在info.plist文件中,我添加了以下条目:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>...</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>...</string>
<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array> 

在我的ViewController中,我调用了startLocationServices函数。目前,我将应用程序的定位数据跟踪授权设置为“ .authorizedAlways”。

大约60-130分钟后,位置更新会停止。

为解决这个问题,我已经添加了didFinishLaunchingWithOptions函数,该函数会再次触发位置更新:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    if let launchOptions = launchOptions,
        let isLocationKey = launchOptions[UIApplication.LaunchOptionsKey.location] as? Bool,
        isLocationKey {
        restartServices()

    }
    return true
} 
当使用此功能唤醒应用程序时,在某些测试中我成功获得持续的数据,但有时应用程序在几分钟后再次挂起。
最后,我还尝试了一个定时器,每5分钟重新启动位置跟踪,但似乎这并不影响更新持续时间。
因此,我的问题是是否有一种方法在后台持续接收位置更新,或者我漏掉了某些选项?
先感谢你的帮助。
编辑:我在iOS 12上测试了应用程序,并在5/5个测试中获取了连续的更新。 因此,我猜问题与iOS 13有关。

1
嘿,你解决这个问题了吗? - Abhishek
3
正如我在上一条评论中所述,我可以通过减少后台资源消耗来大幅增加应用程序在暂停状态前的持续时间。 -> 我完全从应用程序中删除了动作收集功能。 -> 当转移到后台时,我降低位置精度并增加距离过滤器,以获取更少的事件, 我停止一些更新UI的任务, 我对其他数据源的收集进行下采样处理,我不会在后台导出我的数据或进行其他工作负载。 现在我能在后台运行约3000分钟。 - mattll
你能帮我看一下这段代码吗? - Abhishek
2
在您的AppDelegate.swift中实现func applicationDidEnterBackground(_ application: UIApplication)和func applicationDidEnterBackground(_ application: UIApplication)函数。在这些函数中访问您的CLLocationManager并设置distanceFilter,desiredAccuracy属性。我还会降低使用的计时器的采样率(例如当前电池状态等使用信息),并在applicationDidBecomeActive方法中结束用于定期更新主视图或反之亦然的计时器。我想玩耍和测试是关键。 - mattll
2个回答

4

代码没有问题!! 我曾经遇到过同样的问题,并在研究后发现以下内容:

在WWDC19主题演讲中,苹果宣布了两个改变iOS 13中位置权限工作方式的变化。第一个变化使用户可以选择只与您的应用程序共享一次他们的位置。这使得尝试位置功能更加容易,并帮助用户保持敏感位置数据的私密性。

第一个值得注意的变化是,即使您调用requestAlwaysAuthorization,用户在权限对话框中仅会获得“刚才”和“使用期间”的选项。如果用户授予您“使用期间”权限并且您尝试在后台扫描位置,则只有在此时用户才会呈现一个对话框以授予后台权限。

因此,当用户授予WhenInUseUsage权限时,您将在CLAuthorizationStatus中获得always,如果用户选择Allow Once,则CLAuthorizationStatus将在应用再次启动时重置为notDetermined

您可以查看此文章以获取详细信息 https://medium.com/q42-engineering/apple-location-permission-ios13-1e0e59002889

这里是视频https://developer.apple.com/videos/play/wwdc2019/705/

编辑

用户授予When In User权限后,iOS会在几天后向用户显示另一个对话框,以更改权限从使用期间到始终允许。

因此,现在没有直接要求用户立即始终允许权限的方法,就像我们之前做的那样。

enter image description here


2
这解决了你的问题吗?我手动将授权级别设置为始终在 -> 设置-> 隐私-> 位置服务但是那并没有解决问题。 - mattll
2
但是即使我设置了“始终允许”标志,应用程序仍然会在某个时候终止。你的应用程序之后是否持续运行? - mattll
1
谢谢您的更新。我已经遇到了那个弹出窗口,而且您也可以在iPhone隐私设置中设置始终通知,但这对我来说并不能解决上述问题。在iOS 12上,我还没有遇到过连续位置跟踪的任何问题,而在iOS 13上,应用程序会在一段时间后被挂起。 - mattll
1
在探索了一段时间后,以下是我的观察:简短地说:当我处于后台时不做太多工作,我就能记录更长时间,直到暂停。我禁用了大部分在后台执行的功能,因此现在只跟踪位置/某些使用信息,并使用核心数据进行存储。此外,当应用程序进入后台模式时,我会更改位置管理器的distanceFilter和desiredAccuracy。 现在,我可以跟踪约3000次而不被暂停。 - mattll
1
有人得到了这个解决方案吗? - Abhishek
显示剩余4条评论

1
这是一个iOS 13的bug。应用程序权限被iOS弄乱了。在设置中显示“始终”,但实际上更像“在使用时”。一个应用程序在后台休眠,而另一个应用程序在同一设备上持续获取位置(在后台)。
要解决此问题,请转到“设置”->搜索具有问题的应用程序->位置->将“始终”更改为“从不”,然后再次更改为“始终”。
不幸的是,您无法在代码中解决此问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接