ios - 后台定位服务在一段时间内停止工作

标签 ios core-location ios-background-mode

我正在开发一个 iOS 应用程序,用户可以将他们的旅行路线保存到服务器(通过 API 发布他们的位置)。我正在努力解决的问题是一些用户报告说他们保存的路线在行程中途中断。具体来说,当用户在 map 上查看他们保存的路线时,有一部分路线只是一条直线,因为不知何故该路线部分的位置没有发送到服务器,或者只是因为设备当时无法接收位置。 奇怪的是,其余的路线是正常记录的,所以定位服务似乎停止工作了一段时间,但之后又重新启动,所以我的应用程序可以正常记录它。

最令人沮丧的是我无法重现这个问题。

以下是用户报告的问题的情况:
- 用户启动应用程序然后锁定设备屏幕并将其放入口袋,他们在整个旅程中没有触摸它。没有电池耗尽或崩溃发生。
- 在行驶了大约 8-9 公里并且一切正常后,路线记录在接下来的 ~ 65 公里处中断,然后在剩余的 ~ 80 公里内再次记录良好。

下面是我的项目设置:
- 具有位置更新功能的 ON 后台模式。
- 从位置服务接收到的位置根据时间戳和准确性进行过滤,并保存到核心数据中,如果位置成功发送到服务器,则带有“isSent”标志标记。这样我的应用程序就可以解决网络连接中断的情况。
- 标有错误“isSent”标志的位置将每 30 秒发送到服务器一次。

我的 LocationManager 代码:

class LocationManager: NSObject, CLLocationManagerDelegate {

    var locationManager: CLLocationManager = {
        var _locationManager = CLLocationManager()
        _locationManager.delegate = self
        _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        _locationManager.activityType = .automotiveNavigation
        _locationManager.allowsBackgroundLocationUpdates = true
        _locationManager.pausesLocationUpdatesAutomatically = false

        return _locationManager
    }()


    func startLocationService() {
        locationManager.startUpdatingLocation()
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.pausesLocationUpdatesAutomatically = false
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        var positionsToSavedToDb: [DbPositionModel] = []

        for location in locations {
            let howRecent = location.timestamp.timeIntervalSinceNow

            guard abs(location.timestamp.timeIntervalSinceNow) < 10 && location.horizontalAccuracy > 0 && location.horizontalAccuracy < 33 else {
                continue
            }

            if self.locations.count > 0 {
                let distanceSinceLastLocation = location.distance(from: self.locations.last!)
                let timeSinceLastLocation = location.timestamp.timeIntervalSince(self.locations.last!.timestamp)
                if (distanceSinceLastLocation < 5 && abs(timeSinceLastLocation) < 10) {
                    continue
                }
            }

            // Create DbPositionModel from location and append to positionsToSavedToDb
        }

        // Save positionsToSavedToDb to core data
    }

    @objc func each30Seconds(_ timer: Timer) {
        // Select in database DbPositionModel objects with false “isSent” flag to send to server
    }
}

你们能帮我找出代码中的黑洞,或者我能做些什么来重现/修复这个问题吗?非常感谢!!!

最佳答案

我觉得你的设置没问题。只有一个问题。当你说它在 60 公里内不工作然后在 80 公里内开始工作时,是不是一直在后台?我的意思是用户不需要进入前台就可以重新开始工作,对吗?

location.horizo​​ntalAccuracy 的限制是 33。您认为它会非常准确。我不确定,也许设备/城市的组合不好,然后你提前回来了。我建议您记录提前退出的原因。他们的城市可能与您的城市不同。我还听说 iPhoneX 的 GPS 即使定位正确,它的 horizo​​ntalAccuracy 返回的数值也很高。这种情况主要发生在 iPhoneX 用户身上吗?

enum LocationAccuracyError: Error {
    case stale(secondsOld: Double)
    case invalid
    case lowAccuracy(metersOff: Double)
}

extension LocationAccuracyError: LocalizedError{
    var errorDescription: String? {
        switch self {
        case .stale(let seconds):
            return NSLocalizedString("location was stale by: \(seconds) seconds", comment: "")
        case .invalid:
            return NSLocalizedString("location was invalid)", comment: "")
        case .lowAccuracy(let metersOff):
            return NSLocalizedString("location's horizontal Accuracy was off by likely more than: \(metersOff) meters" , comment: "")
        }
    }
}

然后有一个这样的函数来检查每个位置。

private func checkLocationAccuracy(from location: CLLocation) throws {

    let ageOfLocation = -location.timestamp.timeIntervalSinceNow

    if ageOfLocation >= maximumAcceptedStale {
        throw LocationAccuracyError.stale(secondsOld: ageOfLocation)
    }

    if location.horizontalAccuracy <= 0 {
        throw LocationAccuracyError.invalid
    }

    if location.horizontalAccuracy > MaximumAcceptedHorizontalAccuracy{
        throw LocationAccuracyError.lowAccuracy(metersOff: location.horizontalAccuracy)
    }
}

你的最终用法是这样的:

do {
       try checkLocationAccuracy(from: location)

   } catch let error {
       writelog("Bad Location: \(error.localizedDescription)")
   }

我还会在您的应用状态周围添加日志,例如添加日志以捕获 didEnterBackground

关于ios - 后台定位服务在一段时间内停止工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52551494/

相关文章:

ios - 导入非常大的数据集时的CoreData和RestKit性能

ios - 将GestureRecognizer添加到由swift3中的storyboard创建的UILable时出现: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0)错误

ios - 根据各种屏幕尺寸自动布局 Collection View

ios - 无法获取 CLLocationManager 的权限提示

ios - 调用 didEnterBackground 后是否可以在主线程上执行某些操作?

android - 在 Cordova 中获取应用程序的安装日期

objective-c - 复制辐射圆,例如MKMapView上的用户位置

按下主页按钮时,Swift CLLocationManager 弹出窗口不会停留

iOS - 应用程序终止时的后台服务

xcode10 - Swift4.2 类型 'UIBackgroundTaskIdentifier'(又名 'Int')没有成员 'invalid'