美文网首页
iOS开发系列--断点下载

iOS开发系列--断点下载

作者: 提呐个莫 | 来源:发表于2018-07-11 15:46 被阅读0次

    使用场景

    iOS开发过程中有时会有下载大文件的需求,如果不对文件做断点下载处理,一旦在下载过程中中断,再次请求会重新开始下载,对用户来说会消耗过多的流量(非WIFI情况下),非常不友好。

    解决方案

    设置请求头Range属性(需要文件服务器支持)。

    DEMO地址

    https://github.com/TMWu/TMDownloadManager

    主要方法

    /**
     *  开启任务下载资源
     *
     *  @param url           下载地址
     *  @param progressBlock 回调下载进度
     *  @param stateBlock    下载状态
     */
    - (void)downloadWithUrl:(NSString *)url progress:(void(^)(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress))progressBlock state:(void(^)(DownloadState state))stateBlock;
    
    /**
     *  查询该资源的下载进度值
     *
     *  @param url 下载地址
     *
     *  @return 返回下载进度值
     */
    - (CGFloat)progressWithUrl:(NSString *)url;
    
    /**
     *  删除该资源
     *
     *  @param url 下载地址
     */
    - (void)deleteFileWithUrl:(NSString *)url;
    
    /**
     *  停止下载任务
     */
    - (void)stopWithUrl:(NSString *)url;
    
    /**
     *  获取文件路径
     */
    - (NSString *)getFilePathWithUrl:(NSString *)url;
    

    TMDownloadManager讲解

    TMDownloadManager使用单例管理。
    通过url作为key,生成随机taskIdentifier进行缓存。
    执行downloadWithUrl:progress:state:时会进行判断:

        //判断url是否为空
        if (!url) return;
        //判断是否已经下载完成
        if ([self isCompletionWithUrl:url]) {
            stateBlock(DownloadStateCompleted);
            NSLog(@"----该资源已下载完成");
            return;
        }
        //判断是否存在该任务
        if ([self.tasks valueForKey:TMFileName(url)]) {
            [self handle:url];
            return;
        }
        // 创建缓存目录文件
        NSFileManager *fileManager = [NSFileManager defaultManager];
        if (![fileManager fileExistsAtPath:TMCachesDirectory]) {
            [fileManager createDirectoryAtPath:TMCachesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
        }
    

    创建请求

        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
        // 创建流
        NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:TMFileFullpath(url) append:YES];
        // 创建请求
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        // 设置请求头
        NSString *range = [NSString stringWithFormat:@"bytes=%f-", TMDownloadLength(url)];
        [request setValue:range forHTTPHeaderField:@"Range"];
        // 创建一个Data任务
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
        //随机生成任务ID
        NSUInteger taskIdentifier = arc4random() % ((arc4random() % 10000 + arc4random() % 10000));
        [task setValue:@(taskIdentifier) forKeyPath:@"taskIdentifier"];
        // 保存任务
        [self.tasks setValue:task forKey:TMFileName(url)];
        TMSessionModel *sessionModel = [[TMSessionModel alloc] init];
        sessionModel.url = url;
        sessionModel.progressBlock = progressBlock;
        sessionModel.stateBlock = stateBlock;
        sessionModel.stream = stream;
        [self.sessionModels setValue:sessionModel forKey:@(task.taskIdentifier).stringValue];
        [self startWithUrl:url];
    

    接收到数据时,写入数据

    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
    {
        TMSessionModel *sessionModel = [self getSessionModel:dataTask.taskIdentifier];
        // 写入数据
        [sessionModel.stream write:data.bytes maxLength:data.length];
        // 下载进度
        NSUInteger receivedSize = TMDownloadLength(sessionModel.url);
        NSUInteger expectedSize = sessionModel.totalLength;
        CGFloat progress = 1.0 * receivedSize / expectedSize;
        sessionModel.progressBlock(receivedSize, expectedSize, progress);
    }
    

    下载完成后关闭流,并从任务列表中删除。

    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
    {
        TMSessionModel *sessionModel = [self getSessionModel:task.taskIdentifier];
        if (!sessionModel) return;
        if ([self isCompletionWithUrl:sessionModel.url]) {
            // 下载完成
            sessionModel.stateBlock(DownloadStateCompleted);
        }
        else if (error){
            NSLog(@"%@", error);
            // 下载失败
            sessionModel.stateBlock(DownloadStateFailed);
        }
        // 关闭流
        [sessionModel.stream close];
        sessionModel.stream = nil;
        // 清除任务
        [self.tasks removeObjectForKey:TMFileName(sessionModel.url)];
        [self.sessionModels removeObjectForKey:@(task.taskIdentifier).stringValue];
    }
    

    相关文章

      网友评论

          本文标题:iOS开发系列--断点下载

          本文链接:https://www.haomeiwen.com/subject/meszuftx.html