Alyoshak
Alyoshak

Reputation: 2746

How to upload an image file in a background session (iOS)?

I am unable to upload an image from my device's Photos in a background session. When I call [session uploadTaskWithRequest:req fromFile:nsurl] the system immediately complains by sending

Failed to issue sandbox extension for file file:///var/mobile/Media/DCIM/103APPLE/IMG_3984.JPG, errno = 1

to the console. (A similar Stack Overflow issue is here)

However, if I create my NSURLSessionConfiguration with [NSURLSessionConfiguration defaultSessionConfiguration] (instead of [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:id], which I need) and if I construct an NSData object out of the NSURL and upload that instead of uploading straight from a file (which is required by a background session) then the upload succeeds. Btw I'm uploading files into our Rackspace Cloud account, and am able to do this successfully with a simple Postman PUT.

The problem occurs in my uploadObject method, which looks like:

-(void) uploadObject:(NSURL*)urlToBeUploadedIn
{
  NSDictionary *headers = @{ @"x-auth-token": state.tokenID,
                           @"content-type": @"image/jpeg",
                           @"cache-control": @"no-cache" };

  // create destination url for Rackspace cloud upload
  NSString *sURL = [NSString stringWithFormat:@"%@/testing_folder/%@.jpg", state.publicURL, [state generateImageName]]; 
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:sURL]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
  [request setHTTPMethod:@"PUT"];
  [request setAllHTTPHeaderFields:headers];

  self.sessionIdentifier = [NSString stringWithFormat:@"my-background-session"];    
  //    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];  // when I use this instead of the line below the sandbox error goes away
  NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:self.sessionIdentifier];
  self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];

  NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromFile:urlToBeUploadedIn];

  [uploadTask resume];
}

My call that invokes uploadObject: looks like:

    PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:state.arrImagesToBeUploaded options:nil];

    PHAsset *phAsset = [fetchResult objectAtIndex:0]; // yes the 0th item in array is guaranteed to exist, above.
    [phAsset requestContentEditingInputWithOptions:nil
                                   completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {

                                       NSURL *imageURL = contentEditingInput.fullSizeImageURL;                           
                                       [self uploadObject:imageURL]; 

                                   }];

Btw I first validate the NSURL I send to uploadObject: with a call to fileExistsAtPath: so I know my reference to the file is good. Finally, my delegate calls

(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)dataIn

(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error does get invoked, although the data

do get called by the server (although the response won't parse) so, I am getting something back from the server which never correctly receives the image.

Upvotes: 0

Views: 647

Answers (1)

Alyoshak
Alyoshak

Reputation: 2746

A solution is to first copy the image to be uploaded into the app's sandbox. I used:

NSError *err;
BOOL bVal = [myNSDataOb writeToURL:myDestinationURL options:0 error:&err];

and copied into my app's 'Documents' directory, but one might also use:

NSError *err;
BOOL bVal = [[NSFileManager defaultManager] copyItemAtURL:myImageURL toURL:myDestinationURL error:&err];

Upvotes: 1

Related Questions