AFHTTPSessionManager block is not called when app

2019-08-10 07:28发布

问题:

My app get a silent push, then do some http request in background using AFNetworking,but it didn't enter the complete block, code is:

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
[manager GET:urlString
  parameters:nil
     success:^(NSURLSessionDataTask *task, id responseObject) {
         NSLog(@"response objece:%@", responseObject);
     }
     failure:^(NSURLSessionDataTask *task, NSError *error) {
         NSLog(@"error:%@", error);
     }];

then I found maybe I could use NSURLSessionConfiguration to config the session:

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.company.backgroundDownloadSession"];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
[manager GET:urlString
  parameters:nil
     success:^(NSURLSessionDataTask *task, id responseObject) {
         NSLog(@"response objece:%@", responseObject);
     }
     failure:^(NSURLSessionDataTask *task, NSError *error) {
         NSLog(@"error:%@", error);
     }];

but AFNetworking crash says:'Terminating app due to uncaught exception 'NSGenericException', reason: 'Data tasks are not supported in background sessions.' What should I do? And I appreciate your help!

回答1:

A couple of thoughts:

  1. Proper background NSURLSessionConfiguration requires NSURLSessionDownloadTask or NSURLSessionUploadTask. The GET method, though, creates NSURLSessionDataTask.

    To use download or upload tasks, you'll have to build your request separately, and then leverage AFURLSessionManager to issue download or upload. Having said that, you can, though, create requests using the various request serializers, if you're trying to create HTTP GET/POST style requests. Just use the AFHTTPRequestSerializer method requestWithMethod.

    For a basic introduction to using AFNetworking in conjunction with background NSURLSessionConfiguration, see https://stackoverflow.com/a/21359684/1271826. You'll have to marry that with the requestWithMethod, discussed above.

    Note, be wary about using the task-specific completion blocks (because the tasks continue even if the app is terminated and these blocks are long gone). As the AFNetworking documentation for the background download tasks says:

    Warning: If using a background NSURLSessionConfiguration on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use setDownloadTaskDidFinishDownloadingBlock: to specify the URL for saving the downloaded file, rather than the destination block of this method.

  2. If you're making a modest request, it may be easier to just ask the OS for a little time to do so if the user happens to leave your app while the request is still in progress. See Executing Finite-Length Tasks section of App Programming Guide for iOS: Background Execution.

    Bottom line, before issuing the request, do something like:

    UIApplication *application = [UIApplication sharedApplication];
    
    bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
        // Clean up any unfinished task business by marking where you
        // stopped or ending the task outright.
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    

    And then in the completion block of the request, you can terminate the background task:

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

    This is only good for finite length tasks, but it probably much easier than trying to do background NSURLSessionConfiguration.