Bart Schoon
Bart Schoon

Reputation: 309

How should I use NSURLSession in backgroundConfiguration to upload chunks of multiple files to Amazon S3 ( iOS7 )

Currently I am working on a project where we need to send a set of photo's and video's to a S3 amazon server. The flow is like this:

-first we ask api to start a transfer and we get an id back (api call)

-transfer id -> request file upload at api -> file_id as response (api call)

-file id -> request chunk upload at api -> amazon data as response (api call)

-upload chunck -> in the NSURLSession in configured in backgroundConfiguration (5mb each upload)

-finish file upload after last chunck-upload(api call)

-finish transfer after last file-upload(api call)


We need to use the api and make calls to it.. also when the app is running in the background.

So what I thought was to use the AFNetworking 2.0 that can upload files in the background and then runs a completion block.


In that completion block the code is like:

 _managerBackground = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];


    - (void)uploadChunkInTheBackGround:(RequestChunkUploadResponse *)requestChunkUploadResponse
    {
        UploadChunkRequest *chunkUploadRequest = [[UploadChunkRequest alloc]initWithRequestChunkUploadResponse:requestChunkUploadResponse];

        APIService *weakSelf = (APIService *)self;

         NSURLSessionUploadTask *uploadTask = [_managerBackground uploadTaskWithRequest:chunkUploadRequest.request fromFile:chunkUploadRequest.fileLocationURL progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
       //code to prepare recursive upload and files
        [weakSelf uploadChunkInTheBackGround:chunkUploadResponse];
    }];

So the difficulty is that we like to execute code and also try do a upload task in the background of iOS7

When the app is connected to the debugger (Xcode) the above sample works. But without it provides this error in the console:

<BKProcessAssertion: 0x178468380> identifier: com.apple.nsnetworkd.handlesession process: YourApp[675] permittedBackgroundDuration: 30.000000 reason: backgroundDownload owner pid:111 preventSuspend  preventThrottleDownUI  preventIdleSleep  preventSuspendOnSleep

So thats not cool :(

Is there a way to run code and also uploading the files in the background..?? Do you have any experience with this?? Or do we ask to much of iOS7??

I hope you can share your thoughts.

Thanks,

Kind Regards,

Bart Schoon

Upvotes: 2

Views: 3050

Answers (1)

lost found
lost found

Reputation: 329

The error that you see on your console is the 30 second limit enforced by iOS for background tasks. Once a NSURLSessionTask has completed in the background. Your app is launched in the background and your app receives a call in the appDelegate. At this point you should be the storing the completion handler, queue up your next upload task and call the completion handler so a new snapshot can be taken and your app is put back to sleep.

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {

   // store completion handler

}

Now i am not sure when exactly the 30 second limit gets enforced. In earlier versions of iOS 7 version, it was enforced only if your app was relaunched after being kicked out of memory but in the latest version (7.0.3) it sometimes gets enforced even in suspended mode.As usual, there isn't much information in the Apple documentation so we need to figure it out based on trial and error.

I think your problem is that your letting the upload continue in the background without ever calling the completion handler and thats why your app crashes. I don't think NSURLSession is meant to upload tons of file continuously in the background.

This is how your upload should be working, assuming we are performing a background and all your api calls are being made in the background.

1) Create and resume a task to call the api to get the ID - call the completion handler.

2) Task finishes in the background and your app is launched. Lets assume you have 30 seconds. You should be first parsing the response that you will get you the ID. Then setup the next task to request the file upload, call completion handler.

3) Tasks finishes in the background and your app is launched again. Now you will be parsing the response giving you the file id and then you setup your next task for chunked upload, call the completion handler.

So basically to summarize, while in the background, you should be calling the completion handler after every task you setup. If you don't, eventually your app will crash.

Calling the completion handler terribly slows down your upload because then you are relying on iOS to relaunch your app whenever it feels like it but at this point i haven't seen a better solution

Upvotes: 8

Related Questions