12

我的应用程序需要在后台跟踪用户位置,但它未能发送“获取”请求。当应用程序进入前台时,http 请求会立即发送。我正在使用 RestKit 处理我的所有网络请求,并按照本教程设置我的后台位置服务。在我的 applicationDidEnterBackground

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

我在我的 applicationDidBecomeActive 委托中停止MonitoringSignificantLocationChange

这是我的 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 中,我将所需的背景模式键和位置服务作为值。

编辑

我还提到了这个过去的 SO answer。我在整个 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];

使用同步请求很好,因为没有 UI 可以中断后台任务

4

3 回答 3

3

重新创建原始建议作为答案

您是否尝试用股票同步 NSURLConnection 替换您的 restKit 调用?– dklt 9 月 20 日

于 2012-09-24T02:21:51.483 回答
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 请求生成的新线程在调用它后会自动终止。

于 2012-09-25T16:59:05.213 回答
-1

当您的应用程序在后台运行时,您可以完成在进入后台之前启动的 HTTP 请求,但不能发起请求。您只能在后台启动某些网络操作(voip、报亭)。

于 2012-09-17T16:40:49.677 回答