【问题标题】:Background location service stops working in a period of time后台定位服务在一段时间内停止工作
【发布时间】:2019-03-04 05:23:47
【问题描述】:

我正在开发一个 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
    }
}

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

【问题讨论】:

  • 在某些情况下,位置实际上无法通过 GPS 或网络获得。请确保您没有在这里处理这种情况。在这些情况下,您无能为力。
  • 嗨@Swapnil Luktuke,问题发生在很远的距离(大约 65 公里)。我不认为在这么大的区域内无法获得位置。你觉得怎么样?
  • 不太可能,但它们可能不可用。尝试从报告此问题的用户那里获取信息。
  • @Swapnil Luktuke,感谢您的建议。
  • 嘿,这里的答案有帮助吗?如果没有,你能留下你需要什么的评论吗?

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


【解决方案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

【讨论】:

  • 嗨@Honey,用户报告说他们只是把手机放在口袋里,直到到达目的地才触摸它。所以我认为一切都发生在背景中。顺便说一句,您的代码看起来很适合检测我的问题,我会应用它并尝试从用户那里获取更多信息。非常感谢兄弟!!!
猜你喜欢
  • 2012-06-25
  • 1970-01-01
  • 2021-07-31
  • 2014-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-03
相关资源
最近更新 更多