Получить текущее местоположение, когда приложение находится в фоновом режиме - PullRequest
0 голосов
/ 12 марта 2019

Я создал приложение, в котором вы можете нажать кнопку запуска. После нажатия кнопки приложение будет получать местоположение пользователя каждые 10 секунд вплоть до нажатия кнопки «Стоп». Когда я покидаю приложение или экран становится черным, на нем больше не будет мест, пока я снова не войду в приложение.

Итак, я сейчас пытаюсь обновить местоположения, когда приложение свернуто. (Я думаю, это называется на заднем плане?), А также, когда экран становится черным. Но мои вопросы:

  1. Должен ли я написать этот код в AppDelegate ?, если это так. Как я могу знать была ли нажата кнопка или нет?
  2. Где именно в AppDelegate я должен добавить код? И как можно Я передаю местоположения обратно в правильный ViewController? (Так как я не может подготовиться к переходу из AppDelegate)

Если вы знаете ответы на эти вопросы, пожалуйста, не стесняйтесь отвечать на них. :) Я был бы очень признателен!

Ответы [ 2 ]

1 голос
/ 12 марта 2019

Лучший способ получить местоположение пользователя в фоновом режиме - это использовать службу определения существенных изменений в соответствии с документацией Apple , чтобы поместить эту функцию в свой класс:

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:

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()

0 голосов
/ 30 марта 2019
  1. Получите разрешение на местоположение для разрешения «Всегда разрешать»
  2. Установка диспетчера местоположения для allowBackgroundLocationUpdates true из вышеописанного способа вы можете получить местоположение в каждом месте изменения сохранить эту информацию и отправить ее на сервер. Ниже приведен пример кода

    typealias LocateMeCallback = (_ местоположение: CLLocation?) -> Void

    /*
     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()
    
...