利用NSURLSession完成的断点续传功能

首先是业务中的.h文件

#import <UIKit/UIKit.h>
#import "DenglSingleton.h"

@protocol DownLoadVCdelegate <NSObject>

-(void)DownloadCompletedWithIndex:(NSInteger)index;

@end

@interface DownLoadVC : UIViewController
DenglSingletonH(DownLoadVC)
@property (nonatomic,copy) NSDictionary *dic;

@property (nonatomic,weak) id<DownLoadVCdelegate> delegate;

@end
#import "DownLoadVC.h"
#import "UIView+denglFrame.h"
#import "DBBackgroundBtn.h"
#import "SVProgressHUD.h"

#define dAllMusicPlistFilePath [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@"text"] stringByAppendingPathComponent:@"allmusic.plist"]
#define filePath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:self.fileName]

@interface DownLoadVC ()<NSURLSessionDataDelegate>
{
    NSString *_downloadTag;
}

@property (strong, nonatomic)  UIImageView *iconImageView;
@property (strong, nonatomic)  UIImageView *bottomImageView;
@property (strong, nonatomic)  UITextView *AppDescritionTextView;
@property (strong, nonatomic)  UILabel *AppNameLabel;
@property (strong, nonatomic) DBBackgroundBtn *downLoadBtn;
@property (nonatomic,strong) UIButton *backBtn;
@property (nonatomic,strong) UIImageView *backBtnImgView;
@property (nonatomic,copy) NSString *currentName;

/** 下载任务 */
@property (nonatomic, strong) NSURLSessionDataTask *task;
/** session */
@property (nonatomic, strong) NSURLSession *session;
/** 写文件的流对象 */
@property (nonatomic, strong) NSOutputStream *stream;
/** 文件的总长度 */
@property (nonatomic, assign) NSInteger totalLength;
/** 文件百分比 */
@property (nonatomic, assign) float p;
/** 文件名字 */
@property (nonatomic, copy) NSString *fileName;
/** 文件url */
@property (nonatomic, strong) NSURL *url;
/** 下载数据保存字典 */
@property (nonatomic, strong) NSMutableDictionary *downloadingListDic;
@end

@implementation DownLoadVC
DenglSingletonM(DownLoadVC)

- (NSURLSession *)session
{
    if (!_session) {
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc]init]];
    }
    return _session;
}

- (NSOutputStream *)stream
{
    if (!_stream) {
        _stream = [NSOutputStream outputStreamToFileAtPath:filePath append:YES];
    }
    return _stream;
}

-(void)startDownloadMusic{
    // 创建请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url];
    // 设置请求头
    // Range : bytes=xxx-xxx
    NSInteger downloadLength = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil][NSFileSize] integerValue];
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-", downloadLength];
    [request setValue:range forHTTPHeaderField:@"Range"];
    
    // 创建一个Data任务
    self.task = [self.session dataTaskWithRequest:request];
    //    NSLog(@"test");
}

-(void)setDic:(NSDictionary *)dic{
    _dic = dic;
    
    self.fileName = [self.dic objectForKey:@"filename"];
    self.url = [NSURL URLWithString:[self.dic objectForKey:@"url"]];
    if (self.currentName == nil) {
        //初始化UI
        [self setUI];
        self.currentName = self.fileName;
        //取出上一次保存的下载进度
        self.downloadingListDic = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]objectForKey:@"downloadingListDic"]];
        if (self.downloadingListDic == nil) {
            self.downloadingListDic = [NSMutableDictionary dictionary];
            [[NSUserDefaults standardUserDefaults] setObject:self.downloadingListDic forKey:@"downloadingListDic"];
            [[NSUserDefaults standardUserDefaults]synchronize];
        }
        self.p = [[self.downloadingListDic objectForKey:self.fileName] floatValue];
        self.downLoadBtn.progress = self.p;
        //
        if (self.p != 0) {
            [self.downLoadBtn setBackgroundImage:[UIImage imageNamed:@"download_pause"] forState:UIControlStateNormal];
        }
        
        
    }else{
        if (![self.currentName isEqualToString:self.fileName]) {
            //取消任务
            self.currentName = self.fileName;
            [self.session invalidateAndCancel];
            self.session = nil;
            //取出上一次保存的下载进度
            self.downloadingListDic = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]objectForKey:@"downloadingListDic"]];
            if (self.downloadingListDic == nil) {
                self.downloadingListDic = [NSMutableDictionary dictionary];
                [[NSUserDefaults standardUserDefaults] setObject:self.downloadingListDic forKey:@"downloadingListDic"];
                [[NSUserDefaults standardUserDefaults]synchronize];
            }
            self.p = [[self.downloadingListDic objectForKey:self.fileName] floatValue];
            self.downLoadBtn.progress = self.p;
            //
            if (self.p != 0) {
                [self.downLoadBtn setBackgroundImage:[UIImage imageNamed:@"download_pause"] forState:UIControlStateNormal];
            }
            self.downLoadBtn.tag = 1;
        }
    }
    [self setDataWithDic:dic];
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    
    [self.downloadingListDic setObject:[NSString stringWithFormat:@"%f",self.p] forKey:self.fileName];
    
    [[NSUserDefaults standardUserDefaults] setObject:self.downloadingListDic forKey:@"downloadingListDic"];
    [[NSUserDefaults standardUserDefaults]synchronize];
}

-(void)setUI{
    [[NSUserDefaults standardUserDefaults]setObject:@"no" forKey:@"begin"];
    self.view.backgroundColor = [UIColor whiteColor];

    //返回按钮
    self.backBtn = [[UIButton alloc]init];
    [self.backBtn addTarget:self action:@selector(clickBackBtn) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.backBtn];
    //
    self.AppNameLabel = [[UILabel alloc]init];
    self.AppNameLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:self.AppNameLabel];
    //
    self.AppDescritionTextView = [[UITextView alloc]init];
    self.AppDescritionTextView.textColor = [UIColor grayColor];
    self.AppDescritionTextView.editable = NO;
    self.AppDescritionTextView.selectable = NO;
    [self.view addSubview:self.AppDescritionTextView];
    //
    self.bottomImageView = [[UIImageView alloc]init];
    [self.view addSubview:self.bottomImageView];
    //
    self.iconImageView = [[UIImageView alloc]init];
    [self.view addSubview:self.iconImageView];
    
    //
    self.downLoadBtn = [[DBBackgroundBtn alloc]init];
    [self.downLoadBtn setBackgroundImage:[UIImage imageNamed:@"download"] forState:UIControlStateNormal];
    self.downLoadBtn.tag = 1;
    self.downLoadBtn.progress = 0;
    [self.downLoadBtn addTarget:self action:@selector(clickdownLoadBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.downLoadBtn];

    //
    self.backBtnImgView = [[UIImageView alloc]init];
    self.backBtnImgView.image = [UIImage imageNamed:@"back_ipad.png"];
    [self.view addSubview:self.backBtnImgView];

}

-(void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];
    [self setUIFrame];
}

-(void)setUIFrame{
    //下载按钮
    self.downLoadBtn.width = 100 / 1136.0 * self.view.height;
    self.downLoadBtn.height = self.downLoadBtn.width;
    self.downLoadBtn.x = (self.view.width - self.downLoadBtn.width)/2;
    self.downLoadBtn.y = 970 / 1136.0 * self.view.height;

    //图标
    self.iconImageView.width = 400 / 1136.0 * self.view.height;
    self.iconImageView.height = self.iconImageView.width;
    self.iconImageView.x = (self.view.width - self.iconImageView.width)/2;
    self.iconImageView.y = 128 / 1136.0 * self.view.height;
    
    //底部图
    self.bottomImageView.width = self.view.width;
    self.bottomImageView.height = 240 / 1136.0 * self.view.height;
    self.bottomImageView.x = 0;
    self.bottomImageView.y = 900 / 1136.0 * self.view.height;

    //AppNameLabel app名称
    self.AppNameLabel.width = self.view.width;
    self.AppNameLabel.height = 36 / 1136.0 * self.view.height;
    self.AppNameLabel.x = 0;
    self.AppNameLabel.y = 585 / 1136.0 * self.view.height;
    self.AppNameLabel.font = [UIFont systemFontOfSize:35 / 1136.0 * self.view.height];
    
    //AppDescritionTextView
    self.AppDescritionTextView.x = 35 / 1136.0 * self.view.height;
    self.AppDescritionTextView.width = self.view.width - self.AppDescritionTextView.x * 2;
    self.AppDescritionTextView.height = 250 / 1136.0 * self.view.height;
    self.AppDescritionTextView.y = 640 / 1136.0 * self.view.height;
    [self.AppDescritionTextView scrollRangeToVisible:NSMakeRange(0, 1)];
    //
    self.AppDescritionTextView.font = [UIFont systemFontOfSize:32 / 1136.0 * self.view.height];
    
    //返回按钮
    self.backBtn.width = 50;
    self.backBtn.height = 50;
    self.backBtn.x = 0;
    self.backBtn.y = 0;
    
    // 15 8 12 25
    self.backBtnImgView.width = 12 / 568.0 * self.view.height;
    self.backBtnImgView.height = 25 / 568.0 * self.view.height;
    self.backBtnImgView.x = 15/ 568.0 * self.view.height;
    self.backBtnImgView.y = 8/ 568.0 * self.view.height;
}

-(void)setDataWithDic:(NSDictionary*)dic{
    //
    NSString *iconImage = [dic objectForKey:@"image"];
    self.iconImageView.image = [UIImage imageNamed:iconImage];
    
    //
    NSString *bottomImage = [dic objectForKey:@"color"];
    self.bottomImageView.image = [UIImage imageNamed:bottomImage];
    
    //
    NSArray *AppNameArr = [dic objectForKey:@"name"];
    NSInteger index = [[NSUserDefaults standardUserDefaults] integerForKey:@"yuyan"];
    self.AppNameLabel.text = [AppNameArr objectAtIndex:index];
    
    //
    NSArray *AppDescritionArr = [dic objectForKey:@"info"];
    self.AppDescritionTextView.text = [AppDescritionArr objectAtIndex:index];
}

- (IBAction)clickdownLoadBtn:(id)sender {
    UIButton *btn = sender;
    if (btn.tag == 1) {//下载
        [self.downLoadBtn setBackgroundImage:[UIImage imageNamed:@"download"] forState:UIControlStateNormal];
        [self startDownloadMusic];
        [self.task resume];
        _downloadTag = @"resume";
    }else if (btn.tag == -1){//停止
        [self.downLoadBtn setBackgroundImage:[UIImage imageNamed:@"download_pause"] forState:UIControlStateNormal];
        if (self.session) {
            [self.session invalidateAndCancel];
            self.session =nil;
        }
        _downloadTag = @"stop";
    }
    btn.tag *= -1;
}

-(void)dealloc{
}

- (void)clickBackBtn {
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark - NSURLSessionDataDelegate
/**
 * 1.接收到响应
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    // 获得服务器这次请求 返回数据的总长度
    NSInteger downloadLength = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil][NSFileSize] integerValue];
    self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + downloadLength;
    
    // 打开流
    [self.stream open];
    // 接收这个请求,允许接收服务器的数据
    completionHandler(NSURLSessionResponseAllow);
}

/**
 * 2.接收到服务器返回的数据
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
    [self.stream write:data.bytes maxLength:data.length];
    // 下载进度
    NSInteger downloadLength = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil][NSFileSize] integerValue];
    self.p = 1.0 * downloadLength / self.totalLength;
    NSLog(@"%f",self.p);
    dispatch_async(dispatch_get_main_queue(), ^{
        self.downLoadBtn.progress = self.p;
    });
}

/**
 * 3.请求完毕(成功\失败)
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    // 关闭流
    [self.stream close];
    self.stream = nil;
    if (!error) {//没有错误信息
        if (task.state == NSURLSessionTaskStateCompleted) {
            NSLog(@"NSURLSessionTaskStateCompleted");
             NSInteger index = [[self.dic objectForKey:@"index"] integerValue];
            //下载完成后,将曲目的下载状态做一次更新,将新的数组更新到plist文件中。
            NSMutableArray *arr = [NSMutableArray arrayWithContentsOfFile:dAllMusicPlistFilePath];
            NSMutableDictionary *dic = [arr objectAtIndex:index];
            [dic setObject:@"1" forKey:@"isDownLoad"];
            if ([arr writeToFile:dAllMusicPlistFilePath atomically:YES]) {
                NSLog(@"writeToFileSuccess");
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.delegate && [self.delegate respondsToSelector:@selector(DownloadCompletedWithIndex:)]) {
                    [self.delegate DownloadCompletedWithIndex:index];
                }
                [self.navigationController popViewControllerAnimated:NO];
            });
        }
    }else{//有错误信息
        if (error.code == 18446744073709550617) {
            NSLog(@"用户取消");
        }else{
            [SVProgressHUD setMinimumDismissTimeInterval:3.5];
            [SVProgressHUD setDefaultStyle:SVProgressHUDStyleDark];
            NSString *str = NSLocalizedString(@"loadFaild", nil);
            [SVProgressHUD showErrorWithStatus:str];
        }
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

 

posted @ 2016-04-15 13:56  Nuius  阅读(848)  评论(0编辑  收藏  举报