4

即使用户不使用应用程序,我也想获取用户位置。现在我可以在按下主页按钮并且应用程序进入后台状态后获取位置,但在几秒钟后位置更新停止。当我杀死应用程序位置更新时停止。这是我在应用程序委托中的代码。

 let locationManager = CLLocationManager()
  var LatitudeGPS = String()
  var LongitudeGPS = String()
  var speedGPS = String()
  var Course = String()
  var Altitude = String()
  var bgtimer = Timer()

func applicationDidEnterBackground(_ application: UIApplication) {

    self.doBackgroundTask()
  }

  func beginBackgroundUpdateTask() {

    backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
      self.endBackgroundUpdateTask()
    })

  }

  func endBackgroundUpdateTask() {
    UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
    self.backgroundUpdateTask = UIBackgroundTaskInvalid
  }
func doBackgroundTask() {

  DispatchQueue.global(qos: .background).async {

    self.beginBackgroundUpdateTask()
    self.StartupdateLocation()
    self.bgtimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.bgtimer(timer:)), userInfo: nil, repeats: true)
    RunLoop.current.add(self.bgtimer, forMode: RunLoopMode.defaultRunLoopMode)
    RunLoop.current.run()
    self.endBackgroundUpdateTask()

  }


}


func bgtimer(timer:Timer!){
  print("Fired from Background ************************************")
  updateLocation()
}
  func StartupdateLocation() {
    locationManager.delegate = self
    locationManager.startUpdatingLocation()
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.distanceFilter = kCLDistanceFilterNone
    locationManager.requestAlwaysAuthorization()
    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.pausesLocationUpdatesAutomatically = false
  }

  func updateLocation() {
locationManager.startUpdatingLocation()
    locationManager.stopUpdatingLocation()
    print("Latitude: \(LatitudeGPS)")
    print("Longitude: \(LongitudeGPS)")
    print("Speed: \(speedGPS)")
    print("Heading: \(Course)")
    print("Altitude BG: \(Altitude)")
    DispatchQueue.main.async {
      print(UIApplication.shared.backgroundTimeRemaining)

    }
  }

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

    LatitudeGPS = String(format: "%.10f", manager.location!.coordinate.latitude)
    LongitudeGPS = String(format: "%.10f", manager.location!.coordinate.longitude)
    speedGPS = String(format: "%.3f", manager.location!.speed)
    Altitude = String(format: "%.3f", manager.location!.altitude)
    Course = String(format: "%.3f", manager.location!.course)

  }
}

我想几秒钟后我的应用程序终止并且位置更新停止了。我想在应用程序终止(操作系统或用户)20 分钟后停止更新位置以保持电池电量。我的位置更新问题在哪里。

4

1 回答 1

21

有几件事要改变。

步骤1:

确保您在项目的功能部分中启用了位置更新后台模式,如下所示

在此处输入图像描述

第2步:

当我杀死应用程序位置更新时停止。

引用苹果文档

如果您启动此服务并且您的应用程序随后终止,则系统会在新事件到达时自动将应用程序重新启动到后台。在这种情况下,选项字典传递给应用程序(:willFinishLaunchingWithOptions:) 和应用程序(:didFinishLaunchingWithOptions:) 应用程序委托的方法包含关键位置,以指示您的应用程序是由于位置事件而启动的。重新启动后,您仍然必须配置位置管理器对象并调用此方法以继续接收位置事件。当您重新启动位置服务时,当前事件会立即传递给您的委托。此外,即使在您启动定位服务之前,您的位置管理器对象的位置属性也会填充最新的位置对象。

链接:https ://developer.apple.com/documentation/corelocation/cllocationmanager/1423531-startmonitoringsignificantlocati

在上述声明中要注意的重要一点是

重新启动后,您仍然必须配置位置管理器对象并调用此方法以继续接收位置事件。

这意味着,您当前的位置管理器不会有太大用处,您应该创建一个新的并配置新实例并startMonitorSignificantLocationChanges再次调用。

因此,iOS 只会在您使用startMonitoringSignificantLocationChanges.

所有这些仅适用于您的应用程序被终止并且 iOS 在接收到位置更新时重新启动它的情况。但是,如果您的应用程序只是在后台,您无需在使用时做任何事情startMonitorSignificantLocationChanges

另一方面startUpdatingLocation,仅当应用程序处于后台/前台模式时才有效。如果您的应用程序被暂停或终止,iOS 将停止更新位置。

如果您启动此服务并且您的应用程序被暂停,系统会停止传递事件,直到您的应用程序再次开始运行(在前台或后台)。如果您的应用程序被终止,则新位置事件的传递将完全停止。因此,如果您的应用需要在后台接收位置事件,则它必须在其 Info.plist 文件中包含 UIBackgroundModes 键(带有位置值)。

链接:https ://developer.apple.com/documentation/corelocation/cllocationmanager/1423750-startupdatinglocation

所以修改你的代码

 locationManager.startMonitoringSignificantLocationChange()

好的,这是关于正确使用startMonitoringSignificantLocationChangesand startupdatinglocation。现在为您的代码中的错误计时。

错误一:

self.bgtimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.bgtimer(timer:)), userInfo: nil, repeats: true)

使用计时器及时获取位置更新。这不是它的工作原理!!!你不能永远运行 Timer。一旦您的应用程序暂停或终止,计时器就会停止。位置管理器会在位置更改时通知应用程序,您应该只依赖它。您无法运行计时器来及时检查位置更新。它不会在挂起或终止状态下运行。

错误2:

  func updateLocation() {
    locationManager.startUpdatingLocation()
    locationManager.stopUpdatingLocation()

为什么在后续语句中开始和停止更新位置?这没有多大意义。

错误3:

func StartupdateLocation() {
    locationManager.delegate = self
    locationManager.startUpdatingLocation()

StartupdateLocation被多次调用,每次调用此方法时,您都在重复调用startUpdatingLocation位置管理器的同一实例。你不必那样做!你可以打电话startUpdatingLocationstartMonitoringSignificantLocationChange只打电话一次。

于 2017-11-15T06:13:39.667 回答