目录

 

1、实现原理

2、初始化临时保存路径

3、开始下载

4、暂停

5、继续下载

6、需要用到的代理

7、优缺点

8、总结


1、实现原理

利用NSURLSessionDownloadTask进行下载,通过代理获取实时下载进度并通过UIProgressView显示出来,在暂停时将已下载文件保存下来,在继续下载时从已下载文件开始下载。

效果图

ios 断点没进来 通知扩展 ios断点续传原理_NSURLSession

2、初始化临时保存路径

self.mPathStr = @"1.tmp";

首先初始化.tmp为后缀的文件路径名。

3、开始下载

// 开始下载
- (void)start
{
    
    NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"1"];
    configuration.allowsCellularAccess = NO; // 允许4G下载

    self.mSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];

    // 从临时路径中获取已下载文件
    NSString * path = [NSTemporaryDirectory() stringByAppendingPathComponent:self.mPathStr];
    self.mDownloadData = [NSData dataWithContentsOfFile:path];
    
    if (self.mDownloadData.length>0) {
        // 继续下载
        [self goonDownloadData];
        return;
    }
    // 开始下载
    NSString * str1 = @"http://www.ytmp3.cn/down/49055.mp3";
    self.mDownloadTask = [self.mSession downloadTaskWithURL:[NSURL URLWithString:str1]];
    [self.mDownloadTask resume];
    
}

NSURLSessionConfiguration在初始化的时候,可以用 [NSURLSessionConfiguration defaultSessionConfiguration] 即默认模式初始化,不过在下载时我们可以用 [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"1"] 来初始化,这个方法通过给定Identifier可以实现后台下载,

在开始方法中先判断临时路径是否已有下载文件,如果已有下载文件则执行继续下载方法,如果下载文件为空则从0开始下载。

4、暂停

// 暂停
-(void)pause
{
    [self.mDownloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
        
        self.mDownloadData = resumeData;
        
        NSString * path = [NSTemporaryDirectory() stringByAppendingPathComponent:self.mPathStr];
        
       
        [self.mDownloadData writeToFile:path atomically:YES];

        self.mDownloadTask = nil;
        
    }];
    
}

暂停通过 cancelByProducingResumeData 方法实现,该方法提供当前下载文件data,将此文件保存到临时路径以便后续继续下载。

5、继续下载

// 继续
-(void)goonDownloadData
{
    NSString * path = [NSTemporaryDirectory() stringByAppendingPathComponent:self.mPathStr];
    NSLog(@"path - %@",path);
    self.mDownloadData = [NSData dataWithContentsOfFile:path];
    
    self.mDownloadTask  = [self.mSession downloadTaskWithResumeData:self.mDownloadData];
    [self.mDownloadTask resume];
    self.mDownloadData = nil;
    
}

在继续下载方法中通过 downloadTaskWithResumeData 方法将临时路径中的下载文件作为重新开始下载的初始文件。

6、需要用到的代理

1)

/**
 下载时调用,可以实时监听下载的进度
 @param session
 @param downloadTask
 @param bytesWritten 本次下载的文件大小
 @param totalBytesWritten 已经下载的数据大小
 @param totalBytesExpectedToWrite 总大小
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    float process = totalBytesWritten * 1.0 / totalBytesExpectedToWrite;
    NSLog(@"process -- %f -- ",process);
    dispatch_async(dispatch_get_main_queue(), ^{
        
        self.mProgressView.progress = process;
        self.mLabel.text = [NSString stringWithFormat:@"%.2f",process];

    });
    
}

此代理方法会调用很多次,可以实时获取下载进度,并且获取本次下载文件大小

2)

/**
 恢复下载时调用

 @param session
 @param downloadTask
 @param fileOffset 恢复下载时开始下载位置(已下载文件大小)
 @param expectedTotalBytes 总大小
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
    float process = fileOffset * 1.0 / expectedTotalBytes;
    NSLog(@"process -- %f -- ",process);
    dispatch_async(dispatch_get_main_queue(), ^{
        
        self.mProgressView.progress = process;
        self.mLabel.text = [NSString stringWithFormat:@"%.2f",process];

    });
    
    
}

此方法为恢复下载时调用,可以获取之前已下载数据大小和文件总大小,可以用于显示默认进度条,不写也没影响

3)

// 下载完成,location 临时文件地址
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    
    NSLog(@" --默认地址:location -  %@ -- ",location);
    
    NSString * path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    path = [path stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
    [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL URLWithString:path] error:nil];
    
    NSLog(@" --转移地址:path - %@ -- ",path);

    
}

此方法为下载完成方法,可以获取下载完成的临时文件路径location:以CFNetworkDownload开头,.tmp为后缀的路径。可以将文件转移到特定的文件路径,方便后续使用。

7、优缺点

优点:实现方便快捷,可以应对一般的断点续传或者短时的后台下载。

缺点:不足之处是不能实现离线下载,或者长时间的后台下载。如果在实现后台下载时,后台自动杀死或者人为杀掉进程,不能实时保存已下载的文件,因此在重启进程时不能获取之前已下载的文件来进行继续下载。

当然我们可以在实时获取下载进度的方法进行保存,但这样实时的保存操作特别耗费资源,因此并不推荐。

8、总结

通过 NSURLSessionDownloadTask 实现断点续传及下载很方便,可以满足大部分功能。

如果需要后台离线下载还是需要用 NSURLSessionDataTask 实现,具体实现方法后续添加。