如何获取用户位置

How to get user location

我每 1 分钟跟踪一次用户位置,这是我的代码:

定位服务:

import CoreLocation
import CoreData

class LocationService: NSObject, CLLocationManagerDelegate {

    static let shared = LocationService()
    var locationManager: CLLocationManager!
    var currentLocation: CLLocation!
    var timer = Timer()
    var bgTask = UIBackgroundTaskInvalid

    func startUpdatingLocation() {
        locationManager = CLLocationManager()
        locationManager?.requestAlwaysAuthorization()
        locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        locationManager?.distanceFilter = kCLDistanceFilterNone
        if #available(iOS 9.0, *) {
            locationManager?.allowsBackgroundLocationUpdates = true
        }
        locationManager?.pausesLocationUpdatesAutomatically = false
        locationManager?.delegate = self
        locationManager?.startUpdatingLocation()
    }

    func stopUpdatingLocation() {
        locationManager?.stopUpdatingLocation()
        timer.invalidate()
    }

    func startMonitoringLocation() {
        stopUpdatingLocation()
        locationManager?.startMonitoringSignificantLocationChanges()
    }

    func changeLocationAccuracy() {
        switch locationManager.desiredAccuracy {
        case kCLLocationAccuracyBestForNavigation:
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
            locationManager.distanceFilter = 99999
        case kCLLocationAccuracyThreeKilometers:
            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
            locationManager.distanceFilter = kCLDistanceFilterNone
        default: break
        }
    }

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

        bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
            UIApplication.shared.endBackgroundTask(self.bgTask)
            self.bgTask = UIBackgroundTaskInvalid
        })

        guard let newLocation = locations.last else {
            return
        }

        let interval = newLocation.timestamp.timeIntervalSinceNow

        if abs(interval) > 5 || locationManager.desiredAccuracy != kCLLocationAccuracyBestForNavigation {
            return
        }

        if newLocation.horizontalAccuracy < 0 {
            return
        }

        if currentLocation == nil && newLocation.horizontalAccuracy > 70  {
            return
        }

        currentLocation = newLocation

        timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(LocationService.changeLocationAccuracy), userInfo: nil, repeats: false)
         changeLocationAccuracy()
    }
}

应用代理:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    if launchOptions?[UIApplicationLaunchOptionsKey.location] != nil {
        LocationService.shared.startUpdatingLocation()
    }

    return true
}

func applicationWillTerminate(_ application: UIApplication) {
    LocationService.shared.startMonitoringLocation()
}

问题是 "didUpdateLocations" 当我将我的应用程序置于后台 20-30 分钟后不再触发。我错过了什么吗?

数据:

---------- 12:33:41 ---------- accuracy: 100.176340566754, distance: 11.9139937140859
---------- 12:34:41 ---------- accuracy: 100.178246394771, distance: 32.2963845078517
---------- 12:35:42 ---------- accuracy: 100.180248268622, distance: 49.5966777976606
---------- 12:36:42 ---------- accuracy: 100.18076613283, distance: 64.632263503595
---------- 12:37:42 ---------- accuracy: 200.000181126858, distance: 106.803446309979
---------- 12:38:42 ---------- accuracy: 100.390802343119, distance: 18.348623950487
---------- 12:39:43 ---------- accuracy: 150.16852207139, distance: 61.2580288221782
---------- 12:40:43 ---------- accuracy: 241.375319855098, distance: 146.902117049143
---------- 12:41:43 ---------- accuracy: 65.0, distance: 7.48921464439474
---------- 12:42:43 ---------- accuracy: 241.000205573651, distance: 146.987877590092
---------- 12:43:44 ---------- accuracy: 65.0, distance: 7.62405179605234
---------- 12:44:44 ---------- accuracy: 65.0, distance: 7.55896269746399
---------- 12:45:44 ---------- accuracy: 150.000249983526, distance: 38.8944066539055
---------- 12:46:44 ---------- accuracy: 241.139359617865, distance: 147.142388706418
---------- 12:47:45 ---------- accuracy: 65.0, distance: 41.9643473786135
---------- 12:48:45 ---------- accuracy: 241.291934833148, distance: 146.675150610266
---------- 12:49:45 ---------- accuracy: 150.039468172195, distance: 16.6128843089604
---------- 12:50:45 ---------- accuracy: 150.16560931905, distance: 48.6389862868337
---------- 12:51:46 ---------- accuracy: 241.07402885546, distance: 147.229614706109
---------- 12:52:46 ---------- accuracy: 65.0, distance: 7.16417432681208
---------- 12:53:46 ---------- accuracy: 241.06579398531, distance: 146.954120891032
---------- 12:54:46 ---------- accuracy: 241.062179914206, distance: 147.876920566931
---------- 12:55:47 ---------- accuracy: 200.04318538883, distance: 38.136053839707
---------- 12:56:47 ---------- accuracy: 200.180955600876, distance: 88.6844648977498
---------- 12:57:47 ---------- accuracy: 150.202552895379, distance: 91.8166552231255
---------- 12:58:47 ---------- accuracy: 65.0, distance: 57.9455407170564
---------- 12:59:47 ---------- accuracy: 150.166229444757, distance: 34.2036925129397
---------- 13:00:48 ---------- accuracy: 101.846177093094, distance: 0.407274786609172
---------- 13:01:48 ---------- accuracy: 102.125798269775, distance: 48.1922586805367
---------- 13:02:48 ---------- accuracy: 100.180877100619, distance: 16.4299711499485
---------- 13:03:49 ---------- accuracy: 150.094327388532, distance: 77.2190821337144
---------- 13:04:49 ---------- accuracy: 241.079810871571, distance: 146.947321088494
---------- 13:05:49 ---------- accuracy: 241.075270825073, distance: 147.896335551892
---------- 13:06:49 ---------- accuracy: 100.101061118372, distance: 16.0482204840386
---------- 13:07:50 ---------- accuracy: 100.091529189521, distance: 5.74914399862917
---------- 13:08:50 ---------- accuracy: 241.051459353993, distance: 146.942813658832
---------- 13:09:50 ---------- accuracy: 65.8078917547627, distance: 7.06633659121004
---------- 13:10:50 ---------- accuracy: 65.8092481623976, distance: 17.3091393420333
---------- 13:11:51 ---------- accuracy: 244.420168771572, distance: 146.920641901086
---------- 13:12:51 ---------- accuracy: 241.000779705485, distance: 146.871849682004
---------- 13:13:51 ---------- accuracy: 241.000203327672, distance: 144.623591144917

提前致谢

我可以想象几个问题。但最有可能的是你没有得到指定的准确度,因为

locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.distanceFilter = kCLDistanceFilterNone

我认为不会影响SignificantLocationChanges更新

来自Apple's documentation

After returning a current location fix, the receiver generates update events only when a significant change in the user’s location is detected. It does not rely on the value in the distanceFilter property to generate events. Calling this method several times in succession does not automatically result in new events being generated. Calling stopMonitoringSignificantLocationChanges() in between, however, does cause a new initial event to be sent the next time you call this method.

根据引用,也许您尝试 stopMonitoringSignificantLocationChanges 并重新启动它。

此外,位置更新可能已发送到您的 didUpdateLocations 方法,但无法通过您的准确性检查,例如因为给定的准确性较低等。并且您的计时器方法未被调用为结果。


编辑

// to start location update properly and register for notifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

     LocationService.shared.startUpdatingLocation()
     let settings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
     application.registerUserNotificationSettings(settings)

     return true
}

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

    //.....
    // added local notification to look at the update
    let notification = UILocalNotification()
    notification.alertBody = "Location: \(currentLocation), task: \(bgTask)"
    notification.fireDate = Date().addingTimeInterval(1.0)
    notification.soundName = UILocalNotificationDefaultSoundName
    UIApplication.shared.scheduleLocalNotification(notification)

    timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(LocationService.changeLocationAccuracy), userInfo: nil, repeats: false)
    changeLocationAccuracy()
}

这就是我所做的全部更改。