后台位置服务会在一段时间内停止工作

时间:2018-09-28 08:41:25

标签: ios core-location ios-background-mode

我正在开发一个iOS应用程序,用户可以将行进路线保存到服务器(通过API发布位置)。我正在努力解决的问题是,有几位用户报告说他们保存的路线在旅途中途中断。详细地说,当用户在地图上查看其保存的路线时,路线的一部分只是一条直线,这是因为该路线部分的某个位置没有以某种方式发送到服务器,或者仅仅是因为该设备当时无法接收位置。 奇怪的是,其余路线均正常记录,因此位置服务似乎停止了一段时间,但之后又重新启动,因此我的应用程序可以很好地记录它。

最令人沮丧的是,我无法重现此问题。

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

以下是我的项目设置:
-具有位置更新功能的“打开”中的背景模式。
-从位置服务接收的位置会根据时间戳和准确性进行过滤,如果位置成功发送到服务器,则会使用“ 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
    }
}

你们可以帮助我找出代码中的黑洞,或者我可以做些什么来重现/解决此问题?非常感谢!!!

1 个答案:

答案 0 :(得分:1)

您的设置对我来说很好。只是一个问题。当您说它不在60公里处工作然后又开始在80公里处工作时,是不是一直在后台?我的意思是用户不需要输入前台即可重新开始工作,对吗?

您对location.horizontalAccuracy的限制为33。您认为这将是非常准确的。我不确定,也许设备/城市组合不好,然后您要早点回来。我建议您记录为什么要早退的原因。他们的城市可能与您的城市不同。另外,我还听说过iPhoneX的GPS尽管位置正确,但其horizontalAccuracy返回的数字却很大。这主要是针对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