| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- //
- // HSNSURLSession.m
- // HSDownloadManagerExample
- //
- // Created by hans on 15/8/4.
- // Copyright © 2015年 hans. All rights reserved.
- //
- #import "WSDownloadSession.h"
- #define CunCount 8*1024
- @interface WSDownloadSession()<NSURLSessionDelegate>
- @property (nonatomic,copy)NSString *msgUUID;
- /** 流 */
- @property (nonatomic, strong) NSOutputStream *stream;
- //下载任务
- @property (nonatomic, strong) NSURLSessionDataTask *task;
- @property (nonatomic , strong) NSMutableURLRequest *request;
- /** 下载地址 */
- @property (nonatomic, copy) NSString *url;
- /**
- * 缓存根路径/A/
- */
- @property (nonatomic , copy) NSString *cacheRootPath;
- /**
- * 绝对路径(最后的两个绝对,用来拼接)xxj/之后的路径,(需要传出来,所以带上filename)
- */
- @property (nonatomic , copy) NSString *localPath;
- @property (nonatomic , copy) NSString *attachName;
- @property (nonatomic , copy) NSString *fileMd5;
- /**
- * 附件完整路径/A/xx.yy
- */
- @property (nonatomic , copy) NSString *attachFullPath;
- /**
- * 文件大小描述文件完全路径
- */
- @property (nonatomic , copy) NSString *attachTotalLengthFileFullPath;
- /**
- * 已下载长度
- */
- @property (nonatomic , assign)NSInteger downloadedLength;
- /** 获得服务器这次请求 返回数据的总长度 */
- @property (nonatomic, assign) NSInteger totalLengthSaveFromServer;
- //请求时文件模型告知的实际大小.
- @property (nonatomic , assign) NSInteger totalLengthNeedDownload;
- @property (nonatomic, assign)NSURLSession *session;
- @end
- //取消
- static const NSUInteger SessionCancerCode = -999;
- //超时
- @implementation WSDownloadSession
- + (id)oneDownloadSessionWithFileUrlString:(NSString *)downloadUrl savePath:(NSString *)path localPath:(NSString *)localPath fileMd5:(NSString *)md5 UUID:(NSString *)uuid fileName:(NSString *)fileName downloadedSize:(NSInteger)downloadedSize fileSize:(NSInteger)fileSize progressblock:(DownloadProgressBlock)progressBlock successblock:(DownloadSuccessBlock)successblock failedBlock:(DownloadFailedBlock)failedBlock;
- {
- WSDownloadSession *wsDowunloadSession = [[WSDownloadSession alloc]initOneDownloadSessionWithFileUrlString:downloadUrl savePath:path localPath:localPath fileMd5:md5 UUID:uuid fileName:fileName downloadedSize:downloadedSize fileSize:fileSize progressblock:progressBlock successblock:successblock failedBlock:failedBlock];
-
- return wsDowunloadSession;
-
- }
- //SAVE PATH: .../Library/xxj/cloudstorage
- //localpath /cloudstorage/filename
- // savepath/ localpath /filename
- //...library/xxj/cloudStorage/dada78dafada/xxx.filename
- - (instancetype)initOneDownloadSessionWithFileUrlString:(NSString *)downloadUrl savePath:(NSString *)savePath localPath:(NSString *)localPath fileMd5:(NSString *)md5 UUID:(NSString *)uuid fileName:(NSString *)fileName downloadedSize:(NSInteger)downloadedSize fileSize:(NSInteger)fileSize progressblock:(DownloadProgressBlock)progressBlock successblock:(DownloadSuccessBlock)successblock failedBlock:(DownloadFailedBlock)failedBlock
- {
- if (self = [super init]) {
-
- self.msgUUID = uuid;
- self.fileMd5 = md5;
- self.url = downloadUrl;
- self.totalLengthNeedDownload = fileSize;
- /**
- * 实际效果不大?,还是读取实际的大小.
- */
- self.downloadedLength = downloadedSize;
-
- self.downloadProgressBlock = progressBlock;
- self.downloadSuccessBlock = successblock;
- self.downloadFailedBlock = failedBlock;
- self.attachName = fileName;
-
- //localpath即本地绝对localpath,localpath可以不同,name可以相同.
- self.localPath = localPath;//![localPath isEqualToString:fileName]?[NSString stringWithFormat:@"%@/%@",localPath,fileName]:fileName;//存入数据库中.
- //下载完注意删除
- self.attachTotalLengthFileFullPath = [savePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@_totalLength.plist",fileName,md5]];
- self.attachFullPath = [NSString stringWithFormat:@"%@/%@",savePath,self.localPath];
- self.cacheRootPath = self.attachFullPath.stringByDeletingLastPathComponent;
-
- [self createCacheDirectory];
-
- NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc]init]];
-
- //写入文件专用.
- NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:self.attachFullPath append:YES];
-
- //中文字符的链接处理下
- // 创建请求
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[downloadUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
- self.stream = stream;
-
- self.session = session;
-
- self.request = request;
-
- [self sessionWithNewRequest];
-
- }
-
- return self;
- }
- - (void)sessionWithNewRequest
- {
- //中文字符的链接处理下
- // 创建请求
- NSInteger maxDownloadLength = self.downloadedLength + CunCount;
-
- if (maxDownloadLength > self.totalLengthNeedDownload) {
- maxDownloadLength = self.totalLengthNeedDownload;
- }
- // 设置请求头
- NSString *range = [NSString stringWithFormat:@"bytes=%ld-%ld",self.downloadedLength,maxDownloadLength];
- [self.request setValue:range forHTTPHeaderField:@"Range"];
-
-
- NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.request];
-
- [task resume];
-
- self.task = task;
- }
- /**
- * 创建缓存目录文件
- */
- - (void)createCacheDirectory
- {
- NSFileManager *fileManager = [NSFileManager defaultManager];
- if (![fileManager fileExistsAtPath:self.cacheRootPath]) {
- [fileManager createDirectoryAtPath:self.cacheRootPath withIntermediateDirectories:YES attributes:nil error:NULL];
- }
- }
- //实时获取文件大小
- - (NSInteger)downloadedLength
- {
- return [[[NSFileManager defaultManager] attributesOfItemAtPath:self.attachFullPath error:nil][NSFileSize] integerValue];
- }
- //挂起.
- - (void)handle
- {
-
- if (self.task.state == NSURLSessionTaskStateRunning) {
- [self pause];
- } else {
- [self start];
- }
- }
- /**
- * 开始下载
- */
- - (void)start
- {
-
- [self.task resume];
- }
- /**
- * 暂停下载-如果url相同的话就有问题.
- */
- - (void)pause
- {
- //可能超时,show error,直接cancer吧。
-
- if (!self.task) {
- return;
- }
- [self.task suspend];
-
-
-
- }
- - (void)cancer
- {
- if (!self.task) {
- return;
- }
-
- [self.session finishTasksAndInvalidate];
- [self.session invalidateAndCancel];
-
-
- // 关闭流
- [self.stream close];
- self.stream.delegate = nil;
-
- // 清除任务
- [self.task cancel];
-
- self.task = nil;
- self.stream = nil;
- self.session = nil;
- }
- /**
- * 判断该文件是否下载完成
- */
- - (BOOL)isCompletion
- {
-
- if (self.downloadedLength == self.totalLengthNeedDownload ) {
- return YES;
- }
- return NO;
-
- }
- /**
- * 根据服务端返回的总大小生成的文件 获取该资源总大小
- */
- - (NSInteger)fileTotalLength
- {
- return [[NSDictionary dictionaryWithContentsOfFile:self.attachTotalLengthFileFullPath][self.attachName] integerValue];
- }
- #pragma mrak --
- #pragma mark -- URLSessionDelegate
- /**
- * 接收到响应
- */
- - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
- {
- // 打开流
- if (self.stream.streamStatus != NSStreamStatusOpen) {
- [self.stream open];
- }
- // 接收这个请求,允许接收服务器的数据
- completionHandler(NSURLSessionResponseAllow);
- }
- /**
- * 接收到服务器返回的数据
- */
- - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
- {
- // 写入数据
- [self.stream write:data.bytes maxLength:data.length];
-
- self.downloadedLength += data.length;
- // 下载进度
- NSUInteger receivedSize = self.downloadedLength;
- NSUInteger expectedSize = self.totalLengthNeedDownload;
- CGFloat progress = 1.0 * receivedSize / expectedSize;
-
- if (self.downloadProgressBlock) {
- self.downloadProgressBlock(receivedSize, expectedSize, progress,self.attachFullPath,self.msgUUID);
- }
-
- }
- /**
- * 请求完毕(成功|失败)
- */
- - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
- {
- __weak typeof(self)weakself = self;
-
- task = nil;
- if ([self isCompletion]) {
- // 下载完成
-
- if (weakself.downloadSuccessBlock) {
- weakself.downloadSuccessBlock(weakself.downloadedLength,weakself.localPath,weakself.msgUUID);
- }
-
- [self closeSession];
- }else if (self.downloadedLength < self.totalLengthNeedDownload && !error)
- {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-
- if(weakself.session)[weakself sessionWithNewRequest];
- });
-
- }else if (error && error.code != SessionCancerCode){
- // 下载失败
- if (self.downloadFailedBlock) {
- self.downloadFailedBlock(@"error",self.msgUUID);
- }
-
- [self closeSession];
- }
-
-
- }
- - (void)closeSession
- {
- [self.session finishTasksAndInvalidate];
- [self.session invalidateAndCancel];
-
-
- // 关闭流
- [self.stream close];
- self.stream.delegate = nil;
-
- // 清除任务
- [self.task cancel];
-
- self.request = nil;
- self.task = nil;
- self.stream = nil;
- self.session = nil;
- }
- - (void)dealloc
- {
-
- }
- @end
|