4

How do photo apps upload EVERYTHING from the CameraRoll in the background?

I have the need to upload 100s of photos in the background based on date range. My app is currently using NSURLSession with the following code (I think...) But for this to work, my task scheduler has to copy the JPG to a file in App storage (see: Background Upload With Stream Request Using NSUrlSession in iOS8) before the App goes into background. For 100s of photos this takes too much time and storage.

Is there a way to use a "streams" approach, or to reliably schedule additional NSURLSession tasks from the background? My developer says that CameraRoll photos that are potentially in iCloud would cause background scheduling to fail.

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
NSString *identifier = task.originalRequest.allHTTPHeaderFields[@"X-Image-Identifier"];

NSDictionary *d = [self sessionInfosDictionary];
NSURLSessionTaskInfo *info = d[identifier];
double p = (double)totalBytesSent/(double)totalBytesExpectedToSend;
info.progress = p;
[self saveSessionInfos:d];

for (id<PhotosUploaderDelegate>delegate in _delegates) {
    if ([delegate respondsToSelector:@selector(photoUploader:didUploadDataForAssetWithIdentifier:totalBytesSent:totalBytesExpectedToSend:)]) {
        [delegate photoUploader:self didUploadDataForAssetWithIdentifier:identifier totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
    }
  }
}
Community
  • 1
  • 1
michael
  • 3,521
  • 4
  • 39
  • 61

2 Answers2

1

The task is not trivial, there is a lot of work to do.

Start from [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:] and +[NSURLSession uploadTaskWith...] methods.

You'll see that the tricky part is recovering from upload errors. You'll need to track each background upload in your application, by checking -[NSURLSession getTasksWithCompletionHandler:]. But first start from the beginning, with background session configurations and upload tasks.

Gwendal Roué
  • 3,706
  • 13
  • 32
  • I'm already doing that. The problem (I think) is that NSURLSession needs to work with a file in my App storage, and I don't think it makes sense to copy the ENTIRE CameraRoll into my AppStorage. Plus, I think the file copy needs to happen while my App is in "foreground". I need a way to give NSURLSession a file while my app in is "background" – michael Mar 27 '15 at 09:09
  • Yes, each background upload need a file: you'll indeed need to copy the entire camera roll. And... if the application needs to be in foreground to copy each image... then you're in trouble, I agree... I don't see any answer right now. – Gwendal Roué Mar 28 '15 at 20:35
1

I haven't tried it but maybe you could copy the file and start a new upload task in the background session callback? This way you might be able to copy and upload the files one at a time.

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
   // copy file and schedule new upload task
}
Erik Johansson
  • 1,136
  • 7
  • 22
  • I asked my dev about that, and he said it might be possible if the photos were local on the device. But he also said that the iOS8 photos framework now includes access to photos on iCloud and the API doesn't let you discriminate. So if the photos are not local the background process will timeout before it gets the photo from iCloud. – michael Mar 30 '15 at 14:26
  • If it is not a requirement to upload the iCloud photos I think you should be able to use the PHImageRequestOptions networkAccessAllowed = false to filter on local images only. – Erik Johansson Mar 30 '15 at 22:29
  • On the other hand if you want to upload the iCloud photos as well you might have some luck with the PHCachingImageManager. If you pre cache all images they should be downloaded asynchronously in the background (while the app is running I assume). Eventually you should have all iCloud photos on the local device and then you could upload them with help of the technique in the previous comment, but thats patchy at best :) – Erik Johansson Mar 30 '15 at 22:33
  • I could try that, but to be clear, will the PHCachingImageManager approach work if the device is short on storage space? It doesn't sound like a "streaming" solution – michael Mar 31 '15 at 04:14
  • I'm not sure, I guess the cached images will be purged if storage space is required. If you really need 100% of the images to be uploaded I'm not sure this is the right way to go about it, too many moving parts and too many unknowns. If you have the time though it would be interesting to see if it would work :) – Erik Johansson Mar 31 '15 at 08:50
  • I don't actually need 100%, but the number is often > than available storage space. I'll forward to my dev contractor and see if they can do a quick implementation. – michael Mar 31 '15 at 11:14