iOS NSURLSession后台下载和断点续传

本文介绍了在iOS中使用NSURLSession进行后台下载和断点续传的实现步骤,包括设置backgroundSessionConfigurationWithIdentifier、实现相关代理方法、处理临时文件、复制到Documents目录以及添加暂停和恢复功能。详细讲解了代码逻辑,并展示了界面效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前几天面试被人问到后台下载的问题,当时就GG了,之前写Andriod的时候,用service写过,但是iOS没有做过这方面的。回去后查了一些资料,就有了这篇博文。

NSURLSession出来之后,我们可以很容易实现后台下载这种任务,简单使用backgroundSessionConfigurationWithIdentifier:就OK了。
下面讲解如何实现:

首先让我们在ViewController的类拓展里添加如下代码:

@interface ViewController ()<NSURLSessionDelegate,NSURLSessionDownloadDelegate,NSURLSessionTaskDelegate>

@property (nonatomic,strong) NSURLSession *session;

@property (nonatomic,strong) NSURLSessionDownloadTask *task;

@end

我们在里面声明里NSURLSession和NSURLSessionDownTask的属性,还实现了NSURLSessionDelegate,NSURLSessionDownloadDelegate,NSURLSessionTaskDelegate这三个必须实现的代理。

接着我们去实现下载的方法:


- (void)downloadBackground
{
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"download"];
    //系统根据当前性能自动处理后台任务的优先级
    config.discretionary = YES;

    _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    //下面两个是不同的文件,一个是一张图片,一个是微博,大家可以选择不同的网址去实验
    // http://farm3.staticflickr.com/2846/9823925914_78cd653ac9_b_d.jpg
    // http://dlsw.baidu.com/sw-search-sp/soft/3f/12289/Weibo.4.5.3.37575common_wbupdate.1423811415.exe

    NSURL *url = [NSURL URLWithString:@"http://dlsw.baidu.com/sw-search-sp/soft/3f/12289/Weibo.4.5.3.37575common_wbupdate.1423811415.exe"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    _task = [_session downloadTaskWithRequest:request];

    [_task resume];
}

NSURLSession的固定写法,定义后台下载的NSURLSessionConfiguration,定义session,再定义一个request和task,启动task。

这样就可以了吗?当然不是,我们还需要实现相应的代理方法,再添加下面的方法

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{

    //下载过程不断回调
    NSLog(@"当前进度%f%%",totalBytesWritten * 1.0 / totalBytesExpectedToWrite * 100);

}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{

    //下载结束回调,注意这里得到的文件是一个临时文件,为了保存这个文件,我们需要把它copy到Document目录下

    NSLog(@"file--%@,path--%@",downloadTask.description,location);

}

好了,在viewDidLoad函数中调用downloadBackground,现在运行工程,应该可以看到不断打印的进度,在模拟器按一下command+shift+h回到桌面,发现程序依然在下载,并没有停滞,不过最后发现打印出来的path是.tmp文件,像上面注释说的,这里我们得到的是一个临时文件,我们必须将这个文件copy到Document目录下。当然如果你什么都看不到,只看到一条报错信息,请确保你已经在你的plist文件加入以下键值对:

 <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

为什么要这样写?请度娘!!!!

好了,现在让我们实现copy文件的函数

- (void)copyFileAtPath:(NSString *)path
{
    NSFileManager *fileManager = [NSFileManager defaultManager];

    NSError *error;

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *documentDirectory = [paths objectAtIndex:0];
    NSLog(@"document--%@",documentDirectory);

  //测试图片的网址,改这个  
//    NSString *toPath = [documentDirectory stringByAppendingPathComponent:@"1.jpg"];

    NSString *toPath = [documentDirectory stringByAppendingPathComponent:@"weibo.exe"];

    if (![fileManager fileExistsAtPath:toPath]) {

        [fileManager copyItemAtPath:path toPath:toPath error:&error];

        if (error) {
            NSLog(@"copy error--%@",error.description);
        } 
    }
}

上面这个函数首先得到Document文件夹的路径,再拼接出文件路径,最后就是判断文件是否存在,不存在就复制。

请在下载完成的回调函数里调用这个方法,等到下载完成之后,复制控制台打印的document路径,在桌面按command+shift+g,会弹出前往的窗口,粘贴刚刚复制的路径,点击前往,你会看到这样的图片:

这里写图片描述

做到这里,后台下载就完成了。不过我们可以做得更好一些,让我们给它加上断点续传的功能。先让我们用StoryBoard拉个简单的界面,不熟悉StroyBoard的请自行度娘。界面大概是这样的:

这里写图片描述

接着在类拓展里添加下面的属性:

@property (nonatomic,strong) NSData *data;

@property (weak, nonatomic) IBOutlet UIProgressView *progressView;

记住progressView属性是拉出来的,是拉出来的,是拉出来的。接着再拉出下面三个方法,分别添加如下代码:

- (IBAction)startAction:(UIButton *)sender {
     [self downloadBackground];
}

- (IBAction)pauseAction:(UIButton *)sender {

    if (!_task) {
        return;
    }

    [_task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
        _data = resumeData;
    }];
}

- (IBAction)resumeAction:(UIButton *)sender {

    if (!_data) {
        return;
    }else {
        _task = [_session downloadTaskWithResumeData:_data];
        [_task resume];
    }

}

解释一下上面的代码,首先把downloadBackground方法移到开始按钮的点击事件里,pauseAction主要就是调用cancelByProducingResumeData方法,用data属性记录resumeData,在resumeAction里重新启动task,注意是调用downloadTaskWithResumeData方法。

做到这里还没有完哦,我们的progressView还没有刷新呢。所以在下载过程调用的回调代理里添加代码:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    NSLog(@"当前进度%f%%",totalBytesWritten * 1.0 / totalBytesExpectedToWrite * 100);
    //因为这里不是主线程,所以需要回到主线程刷新UI
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = totalBytesWritten * 1.0 / totalBytesExpectedToWrite;
    });
}

现在再运行,你会看到下面的效果:

这里写图片描述

好了,这就完成了后台下载和断点续传了。代码请点链接,文件夹为后台下载和本地通知

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值