Вызов веб-сервиса в фоновом режиме — 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];
}

Есть ли способ реализовать это с меньшим потреблением батареи.

Я сослался на эта ссылка Я не понимаю, какое решение здесь лучше.


person Dev    schedule 17.12.2015    source источник
comment
Вы хотите загрузить текущее местоположение пользователя, когда приложение находится в фоновом режиме?   -  person Bandish Dave    schedule 17.12.2015
comment
Вы не можете использовать какой-либо код на основе NSTimer в фоновом режиме. Вам нужно будет всегда использовать режим местоположения и использовать вызов вашего делегата, чтобы проверить, пора ли вызывать сервер. Но, хотя вы можете использовать обновления местоположения как возможность опросить свой сервер, это не является удобным для батареи или использования данных. Более эффективным способом для вашего сервера является использование push-уведомлений при появлении новых данных.   -  person Paulw11    schedule 17.12.2015
comment
@BandishDave Да, мне нужно сделать вызов веб-службы на основе местоположения пользователя.   -  person Dev    schedule 17.12.2015
comment
@Dev: я думаю, вам нужно использовать класс менеджера местоположения и вызывать свой веб-сервис внутри метода делегата вместо использования таймера.   -  person Bandish Dave    schedule 17.12.2015
comment
@BandishDave, я пробовал то же самое. но didUpdateLocations вызывается каждую секунду. Поэтому я проверяю продолжительность времени и делаю вызов веб-службы каждую минуту внутри didUpdateLocations. И это будет потреблять больше батареи.   -  person Dev    schedule 17.12.2015
comment
@Dev вызывает веб-службу только тогда, когда вы получите точный результат, при этом Location.horizontalAccuracy больше 0 в методе делегата, и используйте один таймер, который включается с некоторой задержкой, например, от 5 до 10 минут, поэтому батарея не будет потреблять.   -  person Bandish Dave    schedule 17.12.2015


Ответы (1)


AppDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : NSObject  {
    // Instance member of our background task process
    UIBackgroundTaskIdentifier bgTask; 
}

@end

AppDelegate.m

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"Application entered background state.");

    // bgTask is instance variable
    NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);

    bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [application endBackgroundTask:self->bgTask];
            self->bgTask = UIBackgroundTaskInvalid;
        });
    }];

    dispatch_async(dispatch_get_main_queue(), ^{

        if ([application backgroundTimeRemaining] > 1.0) {
            // Start background service synchronously
            [[BackgroundCleanupService getInstance] run];
        }

        [application endBackgroundTask:self->bgTask];
        self->bgTask = UIBackgroundTaskInvalid;

    });
}

В приведенной выше реализации есть пара ключевых строк:

Первая — это строка bgTask = [application beginBackgroundTaskWithExpirationHandler..., которая запрашивает дополнительное время для запуска задач очистки в фоновом режиме.

Второй — это последний блок кода метода делегата, начинающийся с dispatch_async. По сути, это проверка того, осталось ли время для выполнения операции с помощью вызова [application backgroundTimeRemaining]. В этом примере я хочу запустить фоновую службу один раз, но в качестве альтернативы вы можете использовать цикл, проверяющий backgroundTimeRemaining на каждой итерации.

Строка [[BackgroundCleanupService getInstance] run] будет вызовом нашего одноэлементного класса обслуживания, который мы создадим прямо сейчас.

Теперь, когда делегат приложения готов запустить нашу фоновую задачу, нам нужен класс службы, который будет взаимодействовать с веб-сервером. В следующем примере я отправлю фиктивный сеансовый ключ и проанализирую ответ, закодированный в формате JSON. Кроме того, я использую две полезные библиотеки для выполнения запроса и десериализации возвращенного JSON, а именно JSONKit и ASIHttpRequest.

BackgroundCleanupService.h

#import <Foundation/Foundation.h>

@interface BackgroundCleanupService : NSObject

+ (BackgroundCleanupService *)getInstance;

- (void)run;

@end

BackgroundCleanupService.m

#import "BackgroundCleanupService.h"
#import "JSONKit.h"
#import "ASIHTTPRequest.h"

@implementation BackgroundCleanupService

/*
 * The singleton instance. To get an instance, use
 * the getInstance function.
 */
static BackgroundCleanupService *instance = NULL;

/**
 * Singleton instance.
 */

+(BackgroundCleanupService *)getInstance {
    @synchronized(self) {
        if (instance == NULL) {
            instance = [[self alloc] init];
        }
    }
    return instance;
}

- (void)run {

    NSURL* URL = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.example.com/user/%@/endsession", @"SESSIONKEY"]];

    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:URL];

    [request setTimeOutSeconds:20]; // 20 second timeout

    // Handle request response
    [request setCompletionBlock:^{
        NSDictionary *responseDictionary = [[request responseData] objectFromJSONData];

        // Assume service succeeded if JSON key "success" returned
        if([responseDictionary  objectForKey:@"success"]) {
                NSLog(@"Session ended");
        }
        else {
             NSLog(@"Error ending session");
        }
    }];

    // Handle request failure
    [request setFailedBlock:^{
        NSError *error = [request error];
        NSLog(@"Service error: %@", error.localizedDescription);
    }];

    // Start the request synchronously since the background service
    // is already running on a background thread
    [request startSynchronous];
}

@end

может помочь

person Maulik shah    schedule 17.12.2015
comment
Ссылки на внешние ресурсы приветствуются, но, пожалуйста, добавьте контекст вокруг ссылки, чтобы ваши коллеги-пользователи имели некоторое представление о том, что это такое и почему оно там. Всегда цитируйте наиболее релевантную часть важной ссылки на случай, если целевой сайт недоступен или постоянно отключается. - person Paulw11; 17.12.2015
comment
@Maulik, как долго будет работать bgTask? Сколько раз будет выполняться веб-служба? - person Dev; 17.12.2015
comment
каждый раз запускать при переходе в фоновый режим - person Maulik shah; 17.12.2015
comment
я имею в виду, будет ли он звонить на сервер каждую минуту, даже если приложение находится в фоновом режиме. - person Dev; 17.12.2015
comment
Итак, мне нужно указать фоновый режим для обновления местоположения или фоновой выборки? - person Dev; 17.12.2015
comment
Это не работает для меня. Я сомневаюсь, что это будет работать только в течение нескольких минут. См. developer.radiusnetworks.com/2014/ 13.11. - person Dev; 17.12.2015
comment
И я хочу, чтобы веб-служба работала в фоновом режиме весь день. - person Dev; 17.12.2015
comment
Apple может отклонить ваше приложение... becz каждый раз, когда вы звоните в веб-службу. Сначала решите, когда вы звоните в веб-службу. - person Maulik shah; 17.12.2015
comment
Вы уверены, что Apple отклонит приложение, если я буду звонить в веб-службу каждую минуту, когда приложение находится в фоновом режиме в течение одного дня? - person Dev; 17.12.2015
comment
получить местоположение пользователя, когда приложение открыто в активном состоянии - person Maulik shah; 17.12.2015