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];
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With