【问题标题】:Cannot keep GPS active with app in background, or read location with app in foreground or background无法在后台使用应用程序保持 GPS 处于活动状态,或在前台或后台使用应用程序读取位置
【发布时间】:2016-10-17 22:23:10
【问题描述】:

与此问题相关的应用旨在以高精度跟踪用户位置,包括 GPS 坐标和加速度计读数,持续 30 分钟,即使用户按下了睡眠按钮。

为此,plist 文件和应用功能设置已更改,以反映始终开启导航访问的原因并启用后台进程以提供基于位置的服务。

应用程序在运行时会询问用户 GPS 权限,如果授予权限,则激活此视图控制器(包含以下代码的视图控制器)确实会导致 GPS/导航图标显示在苹果手机。

问题是,到目前为止,下面看到的四个“打印”命令都不会产生任何打印消息,因此“newLocation”和“myLocation”变量都不会产生任何数据。如果此代码非常接近能够满足第一句话中概述的目的,那么问题是“如何修复它?”。如果这是实现目标的坏方法,那么更好的答案将解释应该如何完成。

import UIKit
import CoreMotion
import MapKit
import CoreLocation

class ActiveSession: UIViewController, CLLocationManagerDelegate {
        lazy var locationManager: CLLocationManager! = {
        let manager = CLLocationManager()
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.delegate = self
        return manager
    }()

    func locationManager(_manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        let myLocation:CLLocationCoordinate2D=CLLocationCoordinate2DMake(oldLocation.coordinate.latitude, oldLocation.coordinate.longitude)
        print(myLocation)

        if UIApplication.shared.applicationState == .active {
            print("at least it's active at all")
        } else {
            print(newLocation)
            print("it's active when the app isn't")
        }
    }

     func getPermission () {
        locationManager = CLLocationManager()

        switch CLLocationManager.authorizationStatus() {
        case .denied, .restricted:
            return
        case .notDetermined:
            locationManager!.requestAlwaysAuthorization()
            break
        case .authorizedAlways, .authorizedWhenInUse:
            break
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.getPermission()
        locationManager = CLLocationManager()
        locationManager!.desiredAccuracy = kCLLocationAccuracyBest
        locationManager?.startUpdatingLocation()
    }
}

【问题讨论】:

  • 不要忘记位置管理器的“allowsBackgroundLocationUpdates”属性。
  • 我建议将位置管理器移出视图控制器,并将其放入 AppDelegate 或其自己的对象中,或者是单例,也可以是在 AppDelegate 上持有引用的对象。您可以简化您的getPermission 代码 - 只需调用requestAlwaysAuthorization - 如果尚未授予或拒绝权限,这将请求权限。如果对话框已被回答,则不显示任何内容。

标签: ios swift swift3 cllocationmanager


【解决方案1】:

您正在三个地方创建新的 CLLocationManager 实例——懒惰的 locationManager 初始化器、getPermissionviewDidLoad——在后两个位置中,您既没有设置所需的精度,也没有设置委托。删除locationManager = CLLocationManager() 行,应该会有更好的结果。

【讨论】:

    【解决方案2】:

    正如 ohr 所指出的,需要额外的权限。将以下行添加到惰性 locationManager 初始化程序以纠正此遗漏:

    manager.allowsBackgroundLocationUpdates = true
    

    按照Noah和Paulw11的建议,删除了getPermission函数,改行:

    locationManager = CLLocationManager()
    

    已从 viewDidLoad 中删除,因为存在大量冗余。仅此一项并不能解决问题,而是向 locationManager 函数添加逻辑,以便将最近的地图数据存储到数组中,如下所示:

    let annotation = MKPointAnnotation()
    annotation.coordinate = newLocation.coordinate    
    locations.append(annotation)
    while locations.count > 100 {
        let annotationToRemove = locations.first!
        locations.remove(at: 0)
    }
    

    导致工作代码。此解决方案源自此处的代码:https://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial (谢谢,雷)

    最终代码在前台和后台运行,无需从类中删除任何内容或在 appdelegate 中实现任何内容。

    【讨论】:

    • 考虑允许延迟位置更新以延长电池寿命。 developer.apple.com/reference/corelocation/cllocationmanager/…
    • 与此代码关联的应用程序功能要求在 30 分钟的时间间隔内精确记录用户相对于时间的位置。除非我误解了文档,否则无法通过延迟更新获得该信息。我们的假设是 30 分钟的记录时间足够短,因此导致的电池耗尽是可以容忍的。
    • 它为您提供包括时间戳在内的准确数据,唯一的区别是它记录在您的应用程序之外并偶尔转储给您(根据您的说明)。
    猜你喜欢
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多