2013-09-27 4 views
80

Я пишу приложение, которое требует обновлений фонового местоположения с высокой точностью и низкой частотой. Решение кажется фоновой задачей NSTimer, которая запускает обновления диспетчера местоположений, которые затем немедленно закрываются. Этот вопрос был задан до:Периодические обновления местоположения фона iOS

How do I get a background location update every n minutes in my iOS application?

Getting user location every n minutes after app goes to background

iOS Not the typical background location tracking timer issue

iOS long-running background timer with "location" background mode

iOS full-time background-service based on location tracking

, но я до сих пор получить минимальный пример работающих. Пробовав каждую перестановку вышеприведенных ответов, я собрал исходную точку. Ввод фон:

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     NSLog(@"ending background task"); 
     [[UIApplication sharedApplication] endBackgroundTask:self.bgTask]; 
     self.bgTask = UIBackgroundTaskInvalid; 
    }]; 


    self.timer = [NSTimer scheduledTimerWithTimeInterval:60 
                target:self.locationManager 
               selector:@selector(startUpdatingLocation) 
               userInfo:nil 
               repeats:YES]; 
} 

и метод делегата:

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation { 

    NSLog(@"%@", newLocation); 

    NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining); 
    [self.locationManager stopUpdatingLocation]; 

} 

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

Update: Я нацеливание IOS 7 и, как представляется, некоторые доказательства того, что фоновые задачи ведут себя по-разному:

Start Location Manager in iOS 7 from background task

+0

Вы не указываете, какую версию iOS вы настраиваете. iOS 7 (например) имеет другую систему многозадачности, чем предшественница. –

+0

@JasonWhitehorn Хорошая точка. Я обновил вопрос. – pcoving

+2

@pcoving: Будет ли ваше решение работать, даже если приложение будет убито или прекращено? – Nirav

ответ

58

Кажется, что stopUpdatingLocation является то, что запускает таймер фон сторожевого, поэтому я заменил его в didUpdateLocation с:

[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]; 
[self.locationManager setDistanceFilter:99999]; 

, который, как представляется, эффективно выключить GPS. Селектор для фона NSTimer становится:

- (void) changeAccuracy { 
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; 
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; 
} 

Все, что я делаю периодически переключая точность, чтобы получить с высокой точностью координат через каждые несколько минут, и потому, что locationManager не была остановлена, backgroundTimeRemaining остается на своем максимальное значение. Это уменьшает потребление батареи от ~ 10% в час (с постоянным kCLLocationAccuracyBest в фоновом режиме) до ~ 2% в час на моем устройстве.

+4

Могли бы вы обновить свой вопрос с полным рабочим примером? Что-то вроде: «ОБНОВЛЕНИЕ: Я понял это. Вот мое решение ...» – smholloway

+0

не работает в io7? Пожалуйста, помогите –

+0

@Virussmca. Я вернул предыдущий ответ, который намного более прочен с аналогичной производительностью. Остановка обновлений местоположения в целом, похоже, вызывает состояние гонки (или какой-либо другой недетерминированный сценарий). – pcoving

1

Как о предоставлении ему попробовать с startMonitoringSignificantLocationChanges: API? Он определенно срабатывает с меньшей частотой, и точность достаточно хорошая. Кроме того, он имеет гораздо больше преимуществ, чем использование других locationManager API.

Лот больше относительно этого API уже обсуждался на этом link

+1

Я пробовал этот подход. Это нарушает требование точности - из [docs] (https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/ startMonitoringSignificantLocationChanges): 'Этот интерфейс предоставляет новые события только в том случае, если он обнаруживает изменения на связанных ячейках сотовой связи устройства. – pcoving

1

Вы должны добавить режим обновления местоположения в приложении, добавив следующий ключ в вас info.plist.

<key>UIBackgroundModes</key> 
<array> 
    <string>location</string> 
</array> 

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

+0

Режим обновления местоположения уже находится в файле info.plist.Как я уже упоминал, я получаю обновления до момента ожидания 180 секунд. – pcoving

31
  1. Если у вас есть UIBackgroundModes в вашем PLIST с location ключом, то вам не нужно использовать beginBackgroundTaskWithExpirationHandler метод. Это избыточно. Кроме того, вы используете его неправильно (см here), но это спорный вопрос, так как ваш PLIST установлен.

  2. С UIBackgroundModes location в plist приложение будет продолжать работать в фоновом режиме неограниченно до тех пор, пока работает CLLocationManger. Если вы назовете stopUpdatingLocation в фоновом режиме, приложение остановится и не запустится снова.

    Может быть, вы могли бы назвать beginBackgroundTaskWithExpirationHandler как раз перед вызовом stopUpdatingLocation, а затем после вызова startUpdatingLocation вы могли бы назвать endBackgroundTask, чтобы держать его в фоновом режиме в то время как GPS останавливается, но я никогда не пробовал - это просто идея.

    Другой вариант (который я еще не пробовал) заключается в том, чтобы менеджер местоположения работал в фоновом режиме, но как только вы получите точное местоположение, измените свойство desiredAccuracy на 1000 м или выше, чтобы позволить отключить микросхему GPS (для экономии заряда аккумулятора). Затем через 10 минут, когда вам потребуется другое обновление местоположения, измените desiredAccuracy на 100 м, чтобы включить GPS, пока не получите точное местоположение, повторите.

  3. Когда вы позвоните по телефону startUpdatingLocation на адресной службы, вы должны дать ему время, чтобы получить должность. Вы не должны сразу звонить stopUpdatingLocation. Мы позволяем ему работать максимум 10 секунд или пока не получим не кэшированное высокоточное местоположение.

  4. Вам необходимо отфильтровать места в кешированном месте и проверить точность местоположения, которое вы получаете, чтобы убедиться, что оно соответствует вашей минимально необходимой точности (см. here). Первое обновление, которое вы получите, может составлять 10 минут или 10 дней. Первая точность, которую вы получите, может составлять 3000 м.

  5. Рассмотрите возможность использования значительных API для изменения местоположения. Как только вы получите уведомление о значительных изменениях, вы можете начать CLLocationManager в течение нескольких секунд, чтобы получить положение с высокой точностью. Я не уверен, я никогда не использовал значительные службы изменения местоположения.

+0

Ссылка Apple 'CoreLocation', по-видимому, рекомендует использовать« beginBackgroundTaskWithExpirationHandler »при обработке данных местоположения в фоновом режиме:« Если для приложения iOS требуется больше времени для обработки данных местоположения, он может запросить дополнительное время выполнения фона, используя beginBackgroundTaskWithName: expirationHandler: expirationHandler: метод класса UIApplication. " - https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html – eliocs

+4

не забудьте добавить _locationManager.allowsBackgroundLocationUpdates = YES; для iOS9 +, иначе приложение будет спать после 180 секунд. – kolyancz

+0

@kolyancz Я просто попробовал это на iOS 10.1.1 для iPhone 6+. Потребовалось примерно 17 минут, чтобы он засыпал и запускал 'locationManagerDidPauseLocationUpdates'. Я проверил это поведение в 10 раз! – Honey

42

Я написал приложение с использованием служб местоположения, приложение должно отправить местоположение каждые 10 секунд. И это сработало очень хорошо.

Просто используйте метод «allowDeferredLocationUpdatesUntilTraveled:timeout», следуя документу Apple.

шаги заключаются в следующем:

Обязательно: Регистрация фоновый режим для обновления Местоположение.

1. Создать LocationManger и startUpdatingLocation, с точностью и filteredDistance, как все, что вы хотите:

-(void) initLocationManager  
{ 
    // Create the manager object 
    self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 
    _locationManager.delegate = self; 
    // This is the most important property to set for the manager. It ultimately determines how the manager will 
    // attempt to acquire location and thus, the amount of power that will be consumed. 
    _locationManager.desiredAccuracy = 45; 
    _locationManager.distanceFilter = 100; 
    // Once configured, the location manager must be "started". 
    [_locationManager startUpdatingLocation]; 
} 

2. Чтобы сохранить приложение бежать навсегда с помощью «allowDeferredLocationUpdatesUntilTraveled: Тайм-аут» метод в фоновом режиме, необходимо перезапустить updatingLocation с новым параметром при приложение перемещается в фоновом режиме, как это:

- (void)applicationWillResignActive:(UIApplication *)application { 
    _isBackgroundMode = YES; 

    [_locationManager stopUpdatingLocation]; 
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; 
    [_locationManager setDistanceFilter:kCLDistanceFilterNone]; 
    _locationManager.pausesLocationUpdatesAutomatically = NO; 
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation; 
    [_locationManager startUpdatingLocation]; 
} 

3. App получает updatedLocations как обычно с " locationManager: didUpdateLocations:»обратный вызов:

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
{ 
// store data 
    CLLocation *newLocation = [locations lastObject]; 
    self.userLocation = newLocation; 

    //tell the centralManager that you want to deferred this updatedLocation 
    if (_isBackgroundMode && !_deferringUpdates) 
    { 
     _deferringUpdates = YES; 
     [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10]; 
    } 
} 

4. Но вы должны обрабатывать данные в то "locationManager: didFinishDeferredUpdatesWithError:" обратный вызов для вашей цели

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error { 

    _deferringUpdates = NO; 

    //do something 
} 

5.Примечание: Я думаю, что мы должны сбросить параметры LocationManager каждый раз, когда приложение переключается между фоновым/forground режимом.

+0

Это прекрасно работает, и я чувствую, что это правильный способ сделать, как упоминалось в WWDC в прошлом году! Спасибо за сообщение – prasad1250

+0

Замечательно, что это решило вашу проблему @ prasad1250 ^^ – samthui7

+0

@ samthui7 спасибо, что это работает, но мне нужно получить местоположение после завершения. как это может быть.?? –

8

Когда пришло время начать службу определения местоположения и остановить фоновое задание, фоновая задача должна быть остановлена ​​с задержкой (1 секунда должно быть достаточно). В противном случае служба поиска не запускается. Также Location Service должен оставаться включенным на пару секунд (например, 3 секунды).

Существует коко-контейнер APScheduledLocationManager, который позволяет получать обновления фонового местоположения каждые n секунд с желаемой точностью местоположения.

let manager = APScheduledLocationManager(delegate: self) 
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100) 

репозиторий также содержит пример приложения, написанные на Swift 3.

+1

, этот модуль работает, когда приложение убито? – GIJOW

0

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

LOCATION BACKGROUND UPDATER

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

0

После iOS 8 их несколько изменений в структуре CoreLocation, связанной с фоновым изложением и обновлениями, сделанными apple.

1) Apple представила запрос AlwaysAuthorization для получения обновления местоположения в приложении.

2) Apple представила backgroundLocationupdates для получения местоположения из фона в iOS.

Для выбора местоположения в фоновом режиме вам необходимо включить обновление местоположения в возможностях Xcode.

// 
// ViewController.swift 
// DemoStackLocation 
// 
// Created by iOS Test User on 02/01/18. 
// Copyright © 2018 iOS Test User. All rights reserved. 
// 

import UIKit 
import CoreLocation 

class ViewController: UIViewController { 

    var locationManager: CLLocationManager = CLLocationManager() 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     startLocationManager() 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    internal func startLocationManager(){ 
     locationManager.requestAlwaysAuthorization() 
     locationManager.desiredAccuracy = kCLLocationAccuracyBest 
     locationManager.delegate = self 
     locationManager.allowsBackgroundLocationUpdates = true 
     locationManager.startUpdatingLocation() 
    } 

} 

extension ViewController : CLLocationManagerDelegate { 

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){ 
     let location = locations[0] as CLLocation 
     print(location.coordinate.latitude) // prints user's latitude 
     print(location.coordinate.longitude) //will print user's longitude 
     print(location.speed) //will print user's speed 
    } 

} 
Смежные вопросы