Objective-C

NSURLSessionDownloadTask断点续传在iOS

2018-06-08  本文已影响6人  Colleny_Z

背景

文件下载需要支持断点续传即杀死应用重新启动后未下载完的文件仍要继续下载
当前主要使用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];
}

感谢 & 参考博客

上一篇 下一篇

猜你喜欢

热点阅读