5

A project I am working on needs to upload a video. The post API call for uploading a video needs a multipart body. The code I tried to use is included at the bottom of the question.

The code works perfectly for [NSURLSessionConfiguration defaultSessionConfiguration].

If I change the configuration to [NSURLSessionConfiguration backgroundSessionConfiguration:@"Test Id"], the code crashes because background sessions only support file uploads. The error is:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Upload tasks in background sessions must be from a file'

All of the multipart append methods that can be used in the following method use the AFMultipartBodyStream class. This class streams the upload so it can not be used in a background session since a stream is not a file.

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer]
                         multipartFormRequestWithMethod:@"POST"
                         parameters:params
                         constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
                             NSError *error = nil;
                             [formData appendPartWithFileURL:fileURL
                                                        name:@"uploadFile"
                                                    fileName:[fileURL lastPathComponent]
                                                    mimeType:@"video/quicktime"
                                                       error:&error];
                         } error:&error];

Is it possible to have a NSURLSessionUploadTask with a multi part body that can run in a AFHTTPSessionManager that is using a backgroundSessionConfiguration?

See sample code below:

NSURL *APIURL = [NSURL URLWithString:@"https://www.test.com/uploadVideo"];

NSError *error = nil;

NSDictionary *params = @{ @"token" : @"d5bcf6c2-99ec-4de7-bd87-71918b633b3a",
                          @"title" : @"Test_Video" };

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer]
                         multipartFormRequestWithMethod:@"POST"
                         parameters:params
                         constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
                             NSError *error = nil;
                             [formData appendPartWithFileURL:fileURL
                                                        name:@"uploadFile"
                                                    fileName:filePath
                                                    mimeType:@"video/quicktime"
                                                       error:&error];
                         } error:&error];

[request addValue:@"Basic 12345678901234567890" forHTTPHeaderField:@"Authorization"];

NSLog(@"%@", error);

__weak __typeof(self)weakSelf = self;
__block NSURLSessionUploadTask *task =
[super
 uploadTaskWithStreamedRequest:request
 progress:progress
 completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
     [weakSelf handleCompletionForTask:task
                        responseObject:responseObject
                                 error:error
                               success:successBlock
                               failure:failureBlock];
 }];

[task setTaskDescription:endpoint.name];
[task resume];

2 Answers2

6

There are some strict limitations with background NSURLSessions, regardless of AFNetworking. Upload tasks must use [NSURLSession uploadTaskWithRequest:fromFile:] I used Charles to monitor outgoing HTTP requests from this method and noticed it's using application/octet-stream. There is no way to get around this, at least nothing I've come across tinkering with it the past few days.

JVillella
  • 1,019
  • 1
  • 11
  • 20
  • 1
    I am also facing the same issue but the problem is that there is no documentation that Upload tasks must use [NSURLSession uploadTaskWithRequest:fromFile:]. In iOS7 we get exception when using uploadTaskWithStreamedRequest: with background configuration but on iOS8 there is not exception and everything works fine when app is in foreground but once it get to the background NSStreamEventEndEncountered is called. Kindly refer me any documentation from apple regarding this thing if you know. – Nauman Afzaal Feb 05 '15 at 10:00
  • I found this empirically, but please see [Background Transfer Considerations](https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW44) in the Apple docs, specifically "Only upload and download tasks are supported (no data tasks)." And from a related (SO answer](http://stackoverflow.com/questions/19985353/nsurlsession-uploading-assets-with-background-transfer) "Talked with Apple engineer at Tech Talks event and he confirmed that background NSURLSession supports only file urls." – JVillella Feb 05 '15 at 13:27
2

I have made this work finally.This is possible by using AFHTTPRequestSerializer:requestWithMultipartFormRequest:writingStreamContentsToFile:completionHandler:. Refer https://github.com/AFNetworking/AFNetworking/issues/1874 - Lansing's answer.

tuttu47
  • 481
  • 1
  • 4
  • 19