Запустите приложение Swift 2.0 навсегда в фоновом режиме, чтобы обновить местоположение на сервере

Я написал приведенный ниже код с таймером, который вызывает функцию обратного вызова каждую минуту. Когда приложение переходит на задний план, я запустил еще один таймер, который вызывает тот же метод обратного вызова, но фоновый таймер работает всего три минуты.

Я понимаю, что Apple позволяет выполнять фоновые задачи всего три минуты. Мое приложение больше похоже на приложение отслеживания, которое отслеживает местоположение пользователя каждую минуту, даже когда приложение находится в фоновом режиме, поэтому мне нужно реализовать эту функциональность.

Я узнал, что нужно использовать beginBackgroundTaskWithExpirationHandler, но я не знаю, правильно ли реализована моя реализация.

Примечание. У меня есть необходимые фоновые режимы в регистре plist toApp для обновлений местоположения.

Приветствуется любой рабочий код или ссылки.

override func viewDidLoad() {
    super.viewDidLoad()

    timeInMinutes = 1 * 60

    self.locationManager.requestAlwaysAuthorization()

    self.locationManager.requestWhenInUseAuthorization()

    if CLLocationManager.locationServicesEnabled() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        locationManager.startUpdatingLocation()
    }

    var timer = NSTimer.scheduledTimerWithTimeInterval( timeInMinutes, target: self, selector: "updateLocation", userInfo: nil, repeats: true)
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
    let locValue:CLLocationCoordinate2D = manager.location!.coordinate

    self.latitude = locValue.latitude
    self.longitude = locValue.longitude

    if UIApplication.sharedApplication().applicationState == .Active {

    } else {
        backgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({ () -> Void in
            self.backgroundTimer.invalidate()
            self.backgroundTimer = NSTimer.scheduledTimerWithTimeInterval( 60.0, target: self, selector: "updateLocation", userInfo: nil, repeats: true)
        })
    }
}

func updateLocation() {
    txtlocationLabel.text = String(n)
    self.n = self.n+1

    var timeRemaining = UIApplication.sharedApplication().backgroundTimeRemaining

    print(timeRemaining)

    if timeRemaining > 60.0 {
        self.GeoLogLocation(self.latitude,Longitude: self.longitude) {
            results in
            print("View Controller: \(results)")
            self.CheckResult(String(results))
        }
    } else {
        if timeRemaining == 0 {
            UIApplication.sharedApplication().endBackgroundTask(backgroundTaskIdentifier)
        }

        backgroundTaskIdentifier2 = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({ () -> Void in
            self.backgroundTimer.invalidate()
            self.backgroundTimer = NSTimer.scheduledTimerWithTimeInterval( 60.0, target: self, selector: "updateLocation", userInfo: nil, repeats: true)
        })
    }
}

Ответ 1

Периодические обновления местоположения в IOS немного сложны. Здесь есть хорошая тема, которую вы можете прочитать здесь

iOS прекратит ваше приложение через несколько минут, независимо от того, работает ли ваш таймер или нет. Есть способ обойти это, хотя мне пришлось сделать что-то подобное при написании ионного приложения, чтобы вы могли проверить код для этого здесь, эта ссылка имеет быстрый класс, который управляет периодическими обновлениями местоположения в iOs.

Чтобы получить периодические местоположения в фоновом режиме и не разряжать аккумулятор устройства, вам необходимо играть с точностью записей местоположения, снизить точность определения местоположения менеджера местоположения, задав его желаемую точность для kCLLocationAccuracyThreeKilometers, затем каждый 60 секунд вам нужно изменить точность до kCLLocationAccuracyBest, это позволит делегату получить новое точное обновление местоположения, а затем вернет точность обратно к минимуму. Таймер необходимо инициализировать каждый раз при получении обновления.

Также есть способ пробудить приложение в фоновом режиме после его убийства пользователем, использовать делегат приложения, чтобы приложение прослушивало значительные изменения в местоположении до его уничтожения. Это запустит приложение в фоновом режиме, когда местоположение пользователя совершит большой прыжок (может составлять около 200 мс). Когда приложение просыпается, прекратите мониторинг значительных изменений и перезапустите службы определения местоположения, как обычно, для продолжения периодических обновлений.

Надеюсь, что это поможет.

Обновление

В Swift 2 вам также понадобится:

self.locationManager.allowsBackgroundLocationUpdates = true

Ответ 2

Вы можете использовать библиотеку для отслеживание фонового местоположения, пример использования:

    var backgroundLocationManager = BackgroundLocationManager()

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

     backgroundLocationManager.startBackground() { result in
            if case let .Success(location) = result {
                LocationLogger().writeLocationToFile(location: location)
            }
    }

    return true
}

Работает, когда приложение убито или приостановлено.