【iOS】NSURLSessionDownloadTask断点续传在iOS10.0~10.1上的坑

背景

文件下载需要支持断点续传即杀死应用重新启动后未下载完的文件仍要继续下载
当前主要使用NSURLSessionDownloadTask完成任务文件下载。

坑 & 解决方案

正常情况下只需要拿到上次缓存下来的数据,用系统方法如下:

// resumeData指上次缓存的数据
NSURLSessionDownloadTask *downloadTask = [_session downloadTaskWithResumeData:model.resumeData];

但是在iOS 10.0到10.1上有问题。也就是说通过上述无法找到task。经过研究搜索可通过以下方法寻找解决为了方便,增加NSURLSession分类:

NSURLSessionDownloadTask *downloadTaskdownloadTask = [_session downloadTaskWithCorrectResumeData:model.resumeData];

分类 NSURLSession

- (NSURLSessionDownloadTask *)downloadTaskWithCorrectResumeData:(NSData *)resumeData
{
    NSData *data = [self getCorrectResumeDataWithData:resumeData];
    data = data ? data : resumeData;
    NSURLSessionDownloadTask *task = [self downloadTaskWithResumeData:data];
    NSMutableDictionary *resumeDic = [self getResumeDictionaryWithData:data];
    
    if (resumeDic) {
        if (!task.originalRequest) {
            NSData *originalReqData = resumeDic[resumeOriginalRequest];
            NSURLRequest *originalRequest = [NSKeyedUnarchiver unarchiveObjectWithData:originalReqData];
            if (originalRequest) [task setValue:originalRequest forKey:@"originalRequest"];
        }
        if (!task.currentRequest) {
            NSData *currentReqData = resumeDic[resumeCurrentRequest];
            NSURLRequest *currentRequest = [NSKeyedUnarchiver unarchiveObjectWithData:currentReqData];
            if (currentRequest) [task setValue:currentRequest forKey:@"currentRequest"];
        }
    }
    
    return task;
}

- (NSData *)getCorrectResumeDataWithData:(NSData *)data
{
    if (!data) return nil;

    NSMutableDictionary *resumeDictionary = [self getResumeDictionaryWithData:data];
    if (!resumeDictionary) return nil;

    resumeDictionary[resumeCurrentRequest] = [self getCorrectRequestDataWithData:resumeDictionary[resumeCurrentRequest]];
    resumeDictionary[resumeOriginalRequest] = [self getCorrectRequestDataWithData:resumeDictionary[resumeOriginalRequest]];

    return [NSPropertyListSerialization dataWithPropertyList:resumeDictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:nil];
}

- (NSMutableDictionary *)getResumeDictionaryWithData:(NSData *)data
{
    return [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil];
}

- (NSData *)getCorrectRequestDataWithData:(NSData *)data
{
    if (!data) return nil;
    
    if ([NSKeyedUnarchiver unarchiveObjectWithData:data]) return data;

    NSMutableDictionary *archive = [[NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil] mutableCopy];
    if (!archive) return nil;

    NSInteger i = 0;
    id objectss = archive[@"$objects"];
    while ([objectss[1] objectForKey:[NSString stringWithFormat:@"$%ld", i]]) {
        i++;
    }
    
    NSInteger j = 0;
    while ([archive[@"$objects"][1] objectForKey:[NSString stringWithFormat:@"__nsurlrequest_proto_prop_obj_%ld", j]]) {
        NSMutableArray *array = archive[@"$objects"];
        NSMutableDictionary *dic = array[1];
        id obj = [dic objectForKey:[NSString stringWithFormat:@"__nsurlrequest_proto_prop_obj_%ld", j]];
        if (obj) {
            [dic setValue:obj forKey:[NSString stringWithFormat:@"$%ld", i + j]];
            [dic removeObjectForKey:[NSString stringWithFormat:@"__nsurlrequest_proto_prop_obj_%ld", j]];
            [array replaceObjectAtIndex:1 withObject:dic];
            archive[@"$objects"] = array;
        }
        j++;
    }
    
    if ([archive[@"$objects"][1] objectForKey:@"__nsurlrequest_proto_props"]) {
        NSMutableArray *array = archive[@"$objects"];
        NSMutableDictionary *dic = array[1];
        id obj = [dic objectForKey:@"__nsurlrequest_proto_props"];
        if (obj) {
            [dic setValue:obj forKey:[NSString stringWithFormat:@"$%ld", i + j]];
            [dic removeObjectForKey:@"__nsurlrequest_proto_props"];
            [array replaceObjectAtIndex:1 withObject:dic];
            archive[@"$objects"] = array;
        }
    }

    if ([archive[@"$top"] objectForKey:@"NSKeyedArchiveRootObjectKey"]) {
        [archive[@"$top"] setObject:archive[@"$top"][@"NSKeyedArchiveRootObjectKey"] forKey: NSKeyedArchiveRootObjectKey];
        [archive[@"$top"] removeObjectForKey:@"NSKeyedArchiveRootObjectKey"];
    }

    return [NSPropertyListSerialization dataWithPropertyList:archive format:NSPropertyListBinaryFormat_v1_0 options:0 error:nil];
}

感谢 & 参考博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 昨夜失眠看了一夜的白夜行 晨曦理查叔叔的爸爸抓起理查起床跑步 理查叔叔跑完步冥冥中有些理解: 超越了过多的怜悯趋近...
    杉沐顿开阅读 209评论 0 0
  • 今天,我们一家子去爬赤岩头。赤岩头海拔1547米,位于龙岩大池与永定虎岗交界处的虎岗黄屋境内。 车开到山脚下,我们...
    一缕馨香阅读 1,201评论 0 0
  • 12.12 Beijing . I should abandon my childish behavior and...
    Elawe阅读 345评论 0 0

友情链接更多精彩内容