I have an app that's using background downloads with the new NSURLSession
APIs. When a download cancels or fails in such a way that NSURLSessionDownloadTaskResumeData
is provided, I store the data blob so that it can be resumed later. A very small amount of the time I am noticing a crash in the wild:
Fatal Exception: NSInvalidArgumentException
Invalid resume data for background download. Background downloads must use http or https and must download to an accessible file.
The error occurs here, where resumeData
is the NSData
blob and session
is an instance of NSURLSession
:
if (resumeData) {
downloadTask = [session downloadTaskWithResumeData:resumeData];
...
The data is provided by the Apple APIs, is serialized, and is then deserialized at a later point in time. It may be corrupted, but it is never nil (as the if statement checks).
How can I check ahead of time that the resumeData
is invalid so that I do not let the app crash?
This is the workaround suggested by Apple:
- (BOOL)__isValidResumeData:(NSData *)data{
if (!data || [data length] < 1) return NO;
NSError *error;
NSDictionary *resumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
if (!resumeDictionary || error) return NO;
NSString *localFilePath = [resumeDictionary objectForKey:@"NSURLSessionResumeInfoLocalPath"];
if ([localFilePath length] < 1) return NO;
return [[NSFileManager defaultManager] fileExistsAtPath:localFilePath];
}
Edit (iOS 7.1 is not NDA'd anymore): I got this from a Twitter exchange with an Apple engineer, he suggested what to do, and I wrote the above implementation
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