Подтвердить что ты не робот

IOS background Местоположение не отправляет HTTP-запрос

Мое приложение должно отслеживать местоположение пользователей в фоновом режиме, но оно не отправляет запрос "получить". HTTP-запрос отправляется немедленно, когда приложение выходит на передний план. Я использую RestKit для всех своих сетевых запросов, и я выполнил этот учебник, чтобы настроить службу фоновых местоположений. В моей applicationDidEnterBackground

-(void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgLocationManager = [[CLLocationManager alloc] init];
    self.bgLocationManager.delegate = self;
    [self.bgLocationManager startMonitoringSignificantLocationChanges];
    NSLog(@"Entered Background");
}

и я stopMonitoringSignificantLocationChange в моем делете applicationDidBecomeActive

Это мой делегат locationManager, где я принимаю новое обновленное местоположение и отправляю на сервер

-(void) locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"I am in the background");
    bgTask = [[UIApplication sharedApplication]
                beginBackgroundTaskWithExpirationHandler:
                ^{
                      [[UIApplication sharedApplication] endBackgroundTask:bgTask];
                 }];
                 // ANY CODE WE PUT HERE IS OUR BACKGROUND TASK

    NSString *currentLatitude = [[NSString alloc]
                                  initWithFormat:@"%g",
                                  newLocation.coordinate.latitude];
    NSString *currentLongitude = [[NSString alloc]
                                   initWithFormat:@"%g",
                                   newLocation.coordinate.longitude];
    NSString *webToken = [[NSUserDefaults standardUserDefaults] stringForKey:@"userWebToken"];
    NSLog(@"I am in the bgTask, my lat %@", currentLatitude);

    NSDictionary *queryParams;
    queryParams = [NSDictionary dictionaryWithObjectsAndKeys:webToken, @"auth_token",  currentLongitude, @"lng", currentLatitude, @"lat", nil];
    RKRequest* request = [[RKClient sharedClient] post:@"/api/locations/background_update" params:queryParams delegate:self];
    //default is RKRequestBackgroundPolicyNone
    request.backgroundPolicy = RKRequestBackgroundPolicyContinue;

    // AFTER ALL THE UPDATES, close the task

    if (bgTask != UIBackgroundTaskInvalid)
    {
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
}

Сетевые запросы работают так, как планировалось, но не будут вызваны в фоновом режиме. Есть ли какие-то дополнительные шаги, которые мне нужны? В моем info.plist у меня есть ключ режима Required Background и location-services в качестве значения.

ИЗМЕНИТЬ

Я также упомянул в прошлом ответе SO. Я провел несколько тестов с пометкой журналов во время вызова didUpdateToLocation, и все они были вызваны, но запрос "получить" не был отправлен. Вместо этого, когда я, наконец, запустил приложение на передний план, он отправил все встроенные сетевые запросы (более 10).

ИЗМЕНИТЬ (2) Я добавил RKRequestBackgroundPolicyContinue к моему запросу, но это не изменило моих результатов. (Как вы можете видеть здесь в фоновом режиме загрузить/загрузить для restkit). Я вижу, что Restkit инициализирует хост, но не отправляет запрос до тех пор, пока приложение не станет активным.

ОТВЕТ

RestKit должен делать что-то, что запрещено в фоновом режиме. Использование NSURLRequest отлично работает.

NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.example.com/api/locations/background_update"]];
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setHTTPBody:jsonData];

NSHTTPURLResponse  *response = nil;
[NSURLConnection sendSynchronousRequest:urlRequest
                      returningResponse:&response
                                  error:&error];

Хорошо использовать синхронный запрос, так как нет интерфейса для нарушения фоновых задач

4b9b3361

Ответ 1

Повторное создание исходного предложения в качестве ответа

Попробуйте заменить ваши вызовы restKit синхронным NSURLConnection? - dklt Sep 20

Ответ 2

Я использую точно такой же код, как и вы, и он работает для меня в RestKit. Единственный способ заставить его работать - это создать синхронный запрос (в любом случае это не имеет смысла делать асинхронно в этом контексте!). Пожалуйста, проверьте этот код и сообщите нам, если он работает:

// REMEMBER. We are running in the background if this is being executed.
// We can't assume normal network access.
// bgTask is defined as an instance variable of type UIBackgroundTaskIdentifier

// Note that the expiration handler block simply ends the task. It is important that we always
// end tasks that we have started.

_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:
           ^{
               [[UIApplication sharedApplication] endBackgroundTask:_bgTask];
           }];

// ANY CODE WE PUT HERE IS OUR BACKGROUND TASK

// For example, I can do a series of SYNCHRONOUS network methods (we're in the background, there is
// no UI to block so synchronous is the correct approach here).

NSNumber *latNumber = [NSNumber numberWithDouble:location.coordinate.latitude];
NSNumber *lngNumber = [NSNumber numberWithDouble:location.coordinate.longitude];
NSNumber *accuracyNumber = [NSNumber numberWithDouble:location.horizontalAccuracy];
NSDictionary *params = [NSDictionary dictionaryWithKeysAndObjects:@"lat",latNumber,@"lng",lngNumber,@"accuracy",accuracyNumber, nil];
RKURL *URL = [RKURL URLWithBaseURL:[NSURL URLWithString:SERVER_URL] resourcePath:@"/user/location/update" queryParameters:params];
RKRequest *request = [RKRequest requestWithURL:URL];
request.method = RKRequestMethodGET;
NSLog(@"Sending location to the server");
RKResponse *response = [request sendSynchronously];
if (response.isFailure)
    NSLog(@"Unable to send background location, failure: %@", response.failureErrorDescription);
else {
    NSError *error = nil;
    NSDictionary *parsedBody = [response parsedBody:&error];
    if (YES == [[parsedBody objectForKey:@"result"] boolValue]){
        NSLog(@"Background location sent to server");
    }
    else {
        //Something went bad
        NSLog(@"Failed to send background location");
    }
}
// AFTER ALL THE UPDATES, close the task

if (_bgTask != UIBackgroundTaskInvalid)
{
    [[UIApplication sharedApplication] endBackgroundTask:_bgTask];
    _bgTask = UIBackgroundTaskInvalid;
}

Я почти уверен, что новый поток, созданный для вашего запроса RKClient, автоматически убивается после его вызова.

Ответ 3

Когда вы работаете в фоновом режиме, вы можете завершить HTTP-запрос, который вы начали до того, как вы вошли в фоновый режим, но вы не можете инициировать новый запрос. Вы можете инициировать определенные сетевые операции в фоновом режиме (voip, киоск).