Отправлять обновления местоположения каждые 30 минут в Swift

У меня есть фоновый режим для служб определения местоположения и направленный на отправку местоположения (широты и долготы) на сервер каждые 30 минут. На данный момент я печатаю то же самое в консоли. Кажется, это работает некоторое время, но мне интересно, как мне работать с NSTimer в этом случае. И откуда я должен его называть?

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {

    var window: UIWindow?
    var locationManager = CLLocationManager()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

        self.locationManager.delegate = self
        self.locationManager.startUpdatingLocation() // I know i should be using signification location option here. this is just for testing now.
    }

    func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        self.sendBackgroundLocationToServer(newLocation);
    }

    func sendBackgroundLocationToServer(location: CLLocation) {
        var bgTask = UIBackgroundTaskIdentifier()
        bgTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler { () -> Void in
            UIApplication.sharedApplication().endBackgroundTask(bgTask)
        }

        println(location.coordinate.latitude)

        if (bgTask != UIBackgroundTaskInvalid)
        {
            UIApplication.sharedApplication().endBackgroundTask(bgTask);
            bgTask = UIBackgroundTaskInvalid;
        }
    }

    func applicationWillEnterForeground(application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        application.beginBackgroundTaskWithExpirationHandler{}
    }

    func applicationDidBecomeActive(application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        application.beginBackgroundTaskWithExpirationHandler{}
    }

    func applicationWillTerminate(application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        application.beginBackgroundTaskWithExpirationHandler{}
    }


}

Может быть, вызов application.beginBackgroundTaskWithExpirationHandler{} - плохая идея? Какие варианты я могу использовать здесь?

Ответы

Ответ 1

Идея beginBackgroundTask... заключается в том, чтобы запустить задачу с конечной длиной, так что если пользователь покинет приложение, он будет продолжать работать в фоновом задании в течение некоторого короткого, конечного периода времени (думаю, 3 минуты). И до того, как закончится время, вы должны вызвать endBackgroundTask, иначе приложение будет завершено с завершением.

Итак, к сожалению, механизм фоновой задачи действительно не подходит для вашего желаемого намерения. Тем не менее, существует узкий набор специальных фоновых режимов, предназначенных для продолжения фоновой работы за пределами узкого набора функций (VOIP, аудио и т.д.). Для получения дополнительной информации см. Раздел "Выполнение долгосрочных задач" Руководство по программированию приложений для iOS: Выполнение фона.

Теперь один из этих фоновых режимов предназначен для службы "location". Итак, если это центральная функция вашего приложения, необходимая для правильной функции, вы можете зарегистрироваться в фоновом режиме location, и ваше приложение будет продолжать работать в фоновом режиме. Оттуда вы можете отслеживать обновления местоположения, и если прошло достаточное количество времени, активируйте некоторый процесс. Но если этот режим фонового местоположения не является существенной особенностью вашего приложения, Apple, скорее всего, отклонит ваше приложение для запроса фонового режима, который ему не нужен.


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

Ответ 2

Несколько заметок, поскольку мы боремся с проблемами местоположения и боремся с фоновыми приложениями, которые, похоже, не разбудили нас.

  • NSTimer работает только до тех пор, пока ваше приложение не будет приостановлено. Конечно, он в фоновом режиме, но только потому, что он способен получать уведомления от iOS (APN, location,...). В конце концов, ваш таймер прекратит стрельбу во время работы в BG. Таким образом, вы полагаетесь на один из режимов BG, чтобы пинать вас.

  • Если вы используете CLLocationManager.startUpdatingLocation, вы заметите, что после этого вы перестали получать их. Особенно, когда телефон расслабляется и пытается спать. Это происходит из-за плохо документированной функции, называемой CLLocationManager.pausesLocationUpdatesAutomatically... которая решает прекратить отправку тех, когда установлено значение "true" (параметр DEFAULT). Вы можете установить это значение "false", и вы продолжите получать обновления своей позиции. Который в значительной степени убедится, что ваше приложение делает то, что вы хотите.

  • Как уже отмечалось выше, вы должны убедиться, что когда вы получите обратный вызов вашего locationManager.didUpdateLocations, вы запустите backgroundTask, чтобы ваше приложение работало во время обработки этой информации и отправки сетевых данных. Но вы, кажется, понимаете это.

  • Просто проснуться достаточно долго, чтобы "записать" обновление местоположения не так уж плохо. Просто убедитесь, что вы не создаете свой сетевой код, если только вы явно не достигли ожидаемого 30-минутного ожидания.

Ответ 3

попробуйте следующее:

  • Сделайте синглтон для службы местоположения. Зарегистрировал его с помощью NSNotification
  • В AppDelegate willEnterBackGround вы отправляете уведомление через NSNotificationCenter

то ваш singleton запустит updatingLocation и отправит его на сервер при получении данных о местоположении.