12

私のアプリはバックグラウンドでユーザーの位置を追跡する必要がありますが、「取得」リクエストの送信に失敗しています。アプリがフォアグラウンドになると、すぐに http 要求が送信されます。私はすべてのネットワーク リクエストに RestKit を使用しており、このチュートリアルに従ってバックグラウンド ロケーション サービスをセットアップしました。私のアプリケーションでDidEnterBackground

-(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 には、 Required Background mode キーと location-services が値として含まれています。

編集

この過去の SO answerも参照しました。didUpdateToLocation 呼び出し全体にログを入れていくつかのテストを実行しましたが、それらはすべて呼び出されましたが、「get」リクエストは送信されませんでした。代わりに、最終的にアプリをフォアグラウンドで起動すると、構築されたすべてのネットワーク要求 (10 以上) が送信されました。

EDIT (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

元の提案を回答として再作成する

restKit 呼び出しを標準の同期 NSURLConnection に置き換えてみませんか? – 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 に答える