it-swarm.com.ru

Периодические обновления фона iOS

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

Как я могу получить фоновое обновление местоположения каждые n минут в моем приложении iOS?

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

iOS Не типичная проблема таймера фонового отслеживания местоположения

iOS длительный фоновый таймер с фоновым режимом "местоположение"

iOS полный фоновый сервис на основе отслеживания местоположения

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

- (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, и есть некоторые доказательства того, что фоновые задачи ведут себя по-разному:

Запустить диспетчер местоположения в iOS 7 из фоновой задачи

87
pcoving

Похоже, что 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% в час на моем устройстве.

61
pcoving

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

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

Шаги следующие:

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

1. Создайте LocationManger и startUpdatingLocation с точностью и отфильтрованным расстоянием как хотите:

-(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: timeout" в фоновом режиме, необходимо перезапустить updateLocation с новым параметром, когда приложение переходит в фоновый режим, например:

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

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

3. Приложение получает обновленные местоположения как обычно с обратным вызовом "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 каждый раз, когда приложение переключается между фоновым/фоновым режимами.

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

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

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

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

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

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

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

32
progrmr

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

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

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

Хранилище также содержит пример приложения, написанного на Swift 3.

8
sash

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

Подробнее об этом API уже говорилось на этом ссылка

1
thatzprem

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

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

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

1
aahsanali

После 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
    }

}
0
Tech