当应用程序在后台时检索当前位置

时间:2019-03-12 14:58:25

标签: ios swift cllocationmanager appdelegate

我已经构建了一个可以按开始按钮的应用程序。按下按钮后,应用程序将每隔10秒获取用户位置,直到按下停止按钮为止。当我离开应用程序或屏幕变黑时,除非重新输入应用程序,否则它将无法获得更多位置。

因此,我目前正在尝试在最小化应用程序时更新位置。 (我猜它是在后台调用的?),以及屏幕变黑时。但是我的问题是:

  1. 我是否应该在AppDelegate中编写此代码?我怎么知道 是否按下了按钮?
  2. 我应该在AppDelegate的确切位置添加代码吗?又怎么能 我将位置传递回正确的ViewController? (自从 无法为AppDelegate的segue做任何准备)

如果您知道这些问题的答案,请随时回答。 :)我真的很感激!

2 个答案:

答案 0 :(得分:1)

让用户在后台获取位置的最佳方法是根据apple's documentation使用有意义的更改位置服务,将此功能放在您的班级中:

func startReceivingSignificantLocationChanges() {
    let authorizationStatus = CLLocationManager.authorizationStatus()
    if authorizationStatus != .authorizedAlways {
    // User has not authorized access to location information.
        return
    } 

    if !CLLocationManager.significantLocationChangeMonitoringAvailable() {
    // The service is not available.
        return
    }
    locationManager.delegate = self
    locationManager.startMonitoringSignificantLocationChanges()
}

还有这个功能:

func locationManager(_ manager: CLLocationManager,  didUpdateLocations 
    locations: [CLLocation]) {
       let lastLocation = locations.last!

       // Do something with the location. 
}

因此,您只需要在按钮内调用startReceivingSignificantLocationChanges(),它将调用locationManager(_ manager:CLLocationManager,didUpdateLocations location:[CLLocation]),所以请使用该位置做您想要的事情。

请记住要获得使用位置的许可并停止使用locationManager.stopMonitoringSignificantLocationChanges()

进行跟踪

答案 1 :(得分:0)

  1. 获取“始终允许”的位置权限
  2. 为allowBackgroundLocationUpdates设置位置管理器true 通过以上方式,您可以在每次位置更改时获取位置,并将此信息存储并发送到服务器。下面是示例代码

    typealias LocateMeCallback =(_位置:CLLocation?)->无效

    /*
     LocationTracker to track the user in while navigating from one place to other and store new locations in locations array.
     **/
    class LocationTracker: NSObject {
    
    static let shared = LocationTracker()
    
    var lastLocation: CLLocation?
    var locations: [CLLocation] = []
    
    var previousLocation: CLLocation?
    var isPreviousIsSameAsCurrent: Bool {
        if let previous = previousLocation, let last = lastLocation {
           return previous == last
        }
        return false
    }
    var isAggressiveModeOn = false
    var locationManager: CLLocationManager = {
       let locationManager = CLLocationManager()
       locationManager.allowsBackgroundLocationUpdates = true
       locationManager.pausesLocationUpdatesAutomatically = true
       locationManager.activityType = .automotiveNavigation
       return locationManager
    }()
    
    var locateMeCallback: LocateMeCallback?
    
    var isCurrentLocationAvailable: Bool {
        if lastLocation != nil {
          return true
        }
        return false
    }
    
    func enableLocationServices() {
        locationManager.delegate = self
        switch CLLocationManager.authorizationStatus() {
        case .notDetermined:
            // Request when-in-use authorization initially
            locationManager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            // Disable location features
            print("Fail permission to get current location of user")
        case .authorizedWhenInUse:
            // Enable basic location features
            enableMyWhenInUseFeatures()
       case .authorizedAlways:
            // Enable any of your app's location features
            enableMyAlwaysFeatures()
       }
    }
    
    func enableMyWhenInUseFeatures() {
       locationManager.startUpdatingLocation()
       locationManager.delegate = self
       escalateLocationServiceAuthorization()
    }
    
    func escalateLocationServiceAuthorization() {
        // Escalate only when the authorization is set to when-in-use
        if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
            locationManager.requestAlwaysAuthorization()
        }
    }
    
    func enableMyAlwaysFeatures() {
       enableCoarseLocationFetch()
       locationManager.startUpdatingLocation()
       locationManager.delegate = self
    }
    
    // Enable Rough Location Fetch
    func enableCoarseLocationFetch() {
       isAggressiveModeOn = false
       locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
       locationManager.distanceFilter = 100
    
    }
    
    // Enable Aggressive Location Fetch
    func enableAggressiveLocationFetch() {
        isAggressiveModeOn = true
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        locationManager.distanceFilter = 10
    
    }
    
    func locateMe(callback: @escaping LocateMeCallback) {
        self.locateMeCallback = callback
        if lastLocation == nil {
            enableLocationServices()
        } else {
           callback(lastLocation)
        }
    }
    
    func startTracking() {
         enableLocationServices()
    }
    
    func stopTracking() {
        locationManager.stopUpdatingLocation()
    }
    
    func resetPreviousLocation() {
        previousLocation = nil
    }
    
    private override init() {}
    

    }

    extension LocationTracker: CLLocationManagerDelegate {
    
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    
    
            print(locations)
            guard let location = locations.first else { return }
            guard -location.timestamp.timeIntervalSinceNow < 120, // Validate only location fetched recently
                location.horizontalAccuracy > 0, // Validate Horizontal Accuracy - Ve means Invalid
                location.horizontalAccuracy < 200 // Validate Horizontal Accuracy > 100 M
                else {
                print("invalid location received OR ignore old (cached) updates")
                return
            }
    
            self.locations.append(location)
            lastLocation = location
    
    
            if let activeRide = RideManager.shared.activeRide,
                let _ = AccessTokenHelper.shared.accessToken,
                let activeRideId = activeRide.ride_id,
                let type = activeRide.rideStatusTypeOptional,
                type == .started  {
                //Store Location For A particular Ride after Start
                LocationUpdater.shared.saveInDataBase(rideId: activeRideId, locations: [location])
            }
    
        }
    
        func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
            print(error.localizedDescription)
        }
    
        func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
            enableLocationServices()
        }
    
    }
    
    
    /*
     This class having responsibility of Updating the location on server after n second and update path after n second.
     **/
    class LocationTimer {
        static let time: Double = 30
    }
    
    /*
      class to update locations to server after nth second
     **/
    class LocationUpdater: NSObject {
    
        static let shared = LocationUpdater(n: Double(LocationTimer.time), tracker: LocationTracker.shared)
    
        let n: Double
        private let tracker: LocationTracker
        var timer: Timer! = nil
    
        init(n: Double, tracker: LocationTracker) {
            self.n = n
            self.tracker = tracker
            super.init()
        }
    
        func startUpdater() {
            self.timer?.invalidate()
            self.timer = nil
            self.timer = Timer.scheduledTimer(timeInterval: n, target: self, selector: #selector(updateLocationsToServer), userInfo: nil, repeats: true)
            self.timer.fire()
        }
    
        func stopUpdater() {
            self.timer?.invalidate()
            self.timer = nil
        }
    
        @objc func updateLocationsToServer() {
    // update to server
     }
    }
    
    
    // usage 
    LocationTracker.shared.startTracking()
    LocationUpdater.shared.startUpdater()