iOS 中视频下载的断点续传

最近项目中遇到一个需求:在视频下载的时候能够暂停保存,能够显示下载进度,在下次进入界面的时候后能够继续下载,要求显示已下载的百分比;列表内能同时下载多个视频文件。思路如下:

1、在执行下载任务时,获取本次下载文件大小,下载一部分的同时写入到本地文件中,动态显示下载进度。


2、暂停下载。



3、继续下载任务,获取本地已下载文件大小。获取继续下载的任务的文件大小。



#import "DownloadHandle.h"

@interface  DownloadHandle ()

@property (nonatomic , copy) NSString  *  downloadCompletePath;//下载完成路径

@property (nonatomic , strong) NSOutputStream * outputStream;//输出流;

@property (nonatomic , assign) NSInteger currentLength;//当前下载的长度

@property (nonatomic , assign) NSInteger totalLength;//全部下载长度

@property (nonatomic , copy)void(^completeFn)(NSError * error);

@property (nonatomic , copy)void(^recieveFn)(CGFloat progress);

@implementation DownloadHandle

-(void)dealloc

[self.dataTask suspend];

self.dataTask = nil;

[self.outputStream close];

self.outputStream = nil;

初始化函数

@param url 下载地址

@param filePath 文件名

@param recieveFn 接受到数据的回调

@param completeFn 下载完成后的回调

@return 实例对象

-(instancetype)initWithUrl:(NSString *)url

filePath:(NSString *)filePath

recieveFn:(void(^)(CGFloat progress))recieveFn

completeFn:(void(^)(NSError *error))completeFn

if(self = [super init])

_url = url;

self.downloadCompletePath = filePath;

self.completeFn = completeFn;

self.recieveFn = recieveFn;

NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];

NSInteger currentDataSize = [self getCurrentDataSize];

NSString * range = [NSString stringWithFormat:@"bytes=%zd-",currentDataSize];

if(currentDataSize != 0)

_currentLength = currentDataSize;

request.timeoutInterval = 0;

[request setValue:range forHTTPHeaderField:@"Range"];

self.dataTask = [self.session dataTaskWithRequest:request];

[self.dataTask resume];

return self;

-(void)pauseDownload

[self.dataTask suspend];

@param recieveFn 继续下载以后的回调

@param completeFn 下载完成的回调

-(void)continueDownloadWithRecieveFn:(void(^)(CGFloat progress))recieveFn

completeFn:(void(^)(NSError *error))completeFn

_recieveFn = recieveFn;

_completeFn = completeFn;

if(self.dataTask )

NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:_url]];

NSInteger currentDataSize = [self getCurrentDataSize];

NSString * range = [NSString stringWithFormat:@"bytes=%zd-",currentDataSize];

if(currentDataSize != 0)

_currentLength = currentDataSize;

request.timeoutInterval = 0;

[request setValue:range forHTTPHeaderField:@"Range"];

self.dataTask = [self.session dataTaskWithRequest:request];

[self.dataTask resume];

-(void)stopDownload

[self.dataTask suspend];

self.dataTask = nil;

[self.outputStream close];

self.outputStream = nil;

获取当前已下载的长度

@return 已下载的长度

-(NSInteger)getCurrentDataSize

NSFileManager * manager = [NSFileManager defaultManager];

NSDictionary * dict = [manager attributesOfItemAtPath:self.downloadCompletePath error:nil];

NSInteger size = [dict[@"NSFileSize"] integerValue];

self.currentLength = size;

return size;

获取当前下载进度百分比

@return 下载进度

-(CGFloat)getCurrentProgress

CGFloat progress = [self getCurrentDataSize] * 1.0 /self.totalLength;

return progress;

#pragma mark ----------- NSURLSessionDownloadDelegate ----------

- (void)URLSession:(NSURLSession *)session

dataTask:(NSURLSessionDataTask *)dataTask

didReceiveResponse:(NSHTTPURLResponse *)response

completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{

NSLog(@"接收到服务器的响应");

NSLog(@"预期长度:%lld",response.expectedContentLength);

self.totalLength = response.expectedContentLength + _currentLength;;

//创建写入流

NSURL * path = [NSURL fileURLWithPath:self.downloadCompletePath];

NSOutputStream * stream = [NSOutputStream outputStreamWithURL:path append:YES];

[stream open];

self.outputStream = stream;

completionHandler(NSURLSessionResponseAllow);

//接受到数据后的回调 会多次回调

-(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data

self.currentLength += data.length;

NSInteger downloadLength =  [self.outputStream write:data.bytes maxLength:data.length];

CGFloat progress = 1.0 *self.currentLength / self.totalLength * 100;

NSLog(@"下载了百分比---->%f %% 下载文件大小%ld,文件总大小:%ld,本地写入的文件大小:%ld", progress,self.currentLength,self.totalLength,downloadLength);

self.recieveFn(progress);

//下载完成

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error

[self.outputStream close];

self.outputStream = nil;

self.completeFn(error);

#pragma mark -------------------------懒加载--------------------------------

-(NSURLSession *)session

if(!_session)

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];