I have BGProcessingTask & BGAppRefreshTask working fine. The main purpose of my use of BGProcessingTask is to upload a file to AWS S3 using multipart/form-data. I have found that any file above about 2.5MB times out after running almost four minutes. If I run the same RESTful api using curl or Postman, I can upload a 25MB file in 3 seconds or less.
I have tried to deliberately set .earliestBeginDate to 01:00 or 02:00 local time on the iPhone, but that does not seem to help.
I use the delegate (yes, I am writing in Objective C) - URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: and find that the iOS system uploads about 140kB every 15 seconds or so.
I am looking for recommendations or insight into how I might enable uploads of 25MB files. I would be happy it I could do just one a day for my use case.
I provide code on how I set up the NSURLSession and NSURLSessionDownloadTask, as it is my guess that if there is something that needs to be modified it is there.
I have to believe there is a solution for this since I read in many posts here and in StackOverflow how developers are using this functionality for uploading many, many files.
NSURLSessionConfiguration *sConf = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:bkto.taskIdentifier]; sConf.URLCache = [NSURLCache sharedURLCache]; sConf.waitsForConnectivity = YES; sConf.allowsCellularAccess = NO; sConf.networkServiceType = NSURLNetworkServiceTypeVideot; sConf.multipathServiceType = NSURLSessionMultipathServiceTypeNone; sConf.discretionary = YES; sConf.timeoutIntervalForResource = kONEHOURINTERVAL; sConf.timeoutIntervalForRequest = kONEMINUTEINTERVAL; sConf.allowsExpensiveNetworkAccess = NO ; sConf.allowsConstrainedNetworkAccess = NO; sConf.sessionSendsLaunchEvents = YES; myURLSession = [NSURLSession sessionWithConfiguration:sConf delegate:self delegateQueue:nil];
And then later in the code...
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:pth]]; request.HTTPMethod = kHTTPPOST; request.HTTPBody = [NSData my body data]; request.timeoutInterval = 60; [request setValue:@"*/*" forHTTPHeaderField:@"Accept"]; [request setValue:@"en-us,en" forHTTPHeaderField:@"Accept-Language"]; [request setValue:@"gzip, deflate, br" forHTTPHeaderField:@"Accept-Encoding"]; [request setValue:@"ISO-8859-1,utf-8" forHTTPHeaderField:@"Accept-Charset"]; [request setValue:@"600" forHTTPHeaderField:@"Keep-Alive"]; [request setValue:@"keep-alive" forHTTPHeaderField:@"Connection"]; NSString *contType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",bnd]; [request setValue:contType forHTTPHeaderField:@"Content-Type"]; [request addValue:[NSString stringWithFormat:@"%lu",(unsigned long)myData.length] forHTTPHeaderField:@"Content-Length"];
and here are a few lines from my logs to show the infrequent multi-part uploads of only small chunks of data by the iOS system:
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 393,216 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 393,216 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: task = BackgroundDownloadTask <76A81A80-4703-4686-8742-A0048EB65108>.<2>, time Fri Mar 7 16:25:27 2025 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 131,072 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 524,288 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: task = BackgroundDownloadTask <76A81A80-4703-4686-8742-A0048EB65108>.<2>, time Fri Mar 7 16:25:42 2025 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 131,072 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 655,360 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: task = BackgroundDownloadTask <76A81A80-4703-4686-8742-A0048EB65108>.<2>, time Fri Mar 7 16:25:56 2025 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 131,072 -[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 786,432
I am looking for recommendations or insight into how I might enable uploads of 25MB files. I would be happy it I could do just one a day for my use case.
I think the issue here is that you're using the background session (and discretionary=YES) and you should just use the default. You're basically telling the system "I don't really need this right now" and that's exactly what it's doing. The background session is useful when you want want to schedule/defer larger transfers, but for small transfers like this it's creating more problems than it solves.
Note that my "rule of thumb" is that timeoutIntervalForResource should generally be in "days+", never minutes. That's particularly true in BGProcessingTask, since the background session is effectively deffering downloads into the same execution window you're running in.
Quick side comment on this point:
I have tried to deliberately set .earliestBeginDate to 01:00 or 02:00 local time on the iPhone, but that does not seem to help.
It's important to understand that you have very little control over when a background task actually runs. You can tell the system when NOT to run the task, but you CANNOT control when the task is actually going to run. Putting that in concrete terms, the system is using heuristics to determine the best time for tasks to run and that's when tasks are GOING to run. You can use earliestBeginDate to defer work "past" that point, but you're not going to change when the work actually runs.
Note that this means you can create configurations that will NEVER fire. For example, if:
-
Your app is used by the user every day.
-
Every time your app runs, reschedules it's BGProcessingTask's to run an 6am the next day.
-
The device's task "window" is from 2am -> 3am (pretty common).
...then you BGProcessingTask will basically never run. Take a look at this post for a rundown of the issues many developers run into this background tasks.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware