mixDownloadOperation.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //
  2. // mixDownloadOperation.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2024/6/27.
  6. //
  7. #import "mixDownloadOperation.h"
  8. #import "mixDownloadManager.h"
  9. #import "NSURLSession+mixDownloadTask.h"
  10. NSString * const mixDownloadCompleteNoti = @"mixDownloadCompleteNoti";
  11. @interface mixDownloadOperation ()
  12. {
  13. mixReceiveResponseOperation _didReceiveResponseCallBack;
  14. mixReceivDataOperation _didReceivDataCallBack;
  15. mixCompleteOperation _didCompleteCallBack;
  16. }
  17. @end
  18. @implementation mixDownloadOperation
  19. - (instancetype)initWith:(NSString *)url session:(NSURLSession *)session {
  20. if (self = [super init]) {
  21. _url = url;
  22. // 初始化下载信息
  23. _currentSize = [self getFileSizeWithURL:url];
  24. // 偏好设置里面存储总数据
  25. _totalSize = [mixDownloadCacheManager totalSizeWith:url];
  26. _timeStamp = [iTools getNowTimeStamp];
  27. // 校验
  28. if (self.currentSize == self.totalSize && self.totalSize != 0) {
  29. return nil;
  30. }
  31. _downloadState = DownloadStateWaiting;
  32. [mixDownloadCacheManager saveFileInfoWithDict:[self downLoadInfoWithFinished:NO]];
  33. _dataTask = [session mix_downloadDataTaskWithURLString:url startSize:_currentSize];
  34. }
  35. return _dataTask ? self : nil;
  36. }
  37. #pragma mark - setups
  38. - (int64_t)getFileSizeWithURL:(NSString *)url {
  39. // // md5文件名加密
  40. // NSString *md5FielName = [[url lastPathComponent] stringByDeletingPathExtension];
  41. // // 获取后缀名
  42. // NSArray *subString = [[url lastPathComponent] componentsSeparatedByString:@"."];
  43. // 拼接后缀名
  44. NSString *urlFileName = [url lastPathComponent];
  45. NSString * decodeUrlFileName= [urlFileName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  46. self.fileName = decodeUrlFileName;
  47. // 创建文件储存路径
  48. if (![[NSFileManager defaultManager] fileExistsAtPath:[mixDownloadCacheManager getFullDirector]]) {
  49. [[NSFileManager defaultManager] createDirectoryAtPath:[mixDownloadCacheManager getFullDirector] withIntermediateDirectories:YES attributes:nil error:nil];
  50. }
  51. // 设置下载路径
  52. self.fullPath = [[mixDownloadCacheManager getFullDirector] stringByAppendingPathComponent:self.fileName];
  53. // 获取下载进度
  54. NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];
  55. // 获取已下载的长度
  56. return [fileInfo[NSFileSize] longLongValue];
  57. }
  58. #pragma mark - mixDownloadOperationProtocol
  59. // 接收到相应时
  60. - (void)operateWithResponse:(NSURLResponse *)response {
  61. // 总的size
  62. if (self.currentSize + response.expectedContentLength == 0) {
  63. HLog(@"下载数据回调异常");
  64. return;
  65. }
  66. self.totalSize = self.currentSize + response.expectedContentLength;
  67. // 创建空的文件夹
  68. if (self.currentSize == 0) {
  69. // 创建空的文件
  70. [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
  71. }
  72. // 创建文件句柄
  73. self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
  74. // 文件句柄移动到文件末尾 位置 // 返回值是 unsign long long
  75. [self.handle seekToEndOfFile];
  76. // 开始下载记录文件下载信息
  77. _downloadState = DownloadStateDoing;
  78. [mixDownloadCacheManager saveFileInfoWithDict:[self downLoadInfoWithFinished:NO]];
  79. // 回调给外界
  80. if (_didReceiveResponseCallBack) {
  81. dispatch_async(dispatch_get_main_queue(), ^{
  82. self->_didReceiveResponseCallBack(self.fullPath);
  83. });
  84. }
  85. }
  86. - (void)operateWithReceivingData:(NSData *)data {
  87. // 获得已经下载的文件大小
  88. self.currentSize += data.length;
  89. HLog(@"currentSize:%lld---progress:%.2f", self.currentSize, 1.00*self.currentSize/self.totalSize);
  90. // long long hhhh = [self.handle seekToEndOfFile];
  91. // HLog(@"hhhh:%lld---handle:%@", hhhh, self.handle);
  92. // 写入文件
  93. [self.handle writeData:data];
  94. // 下载状态 通知代理
  95. if (_didReceivDataCallBack) {
  96. dispatch_async(dispatch_get_main_queue(), ^{
  97. self->_didReceivDataCallBack((NSUInteger)self.currentSize,(NSUInteger)self.totalSize);
  98. });
  99. }
  100. // 下载中通知
  101. [self operationDoningWithOperation:self];
  102. }
  103. - (void)operateWithComplete:(NSError *)error {
  104. // 关闭文件句柄
  105. [self.handle closeFile];
  106. // 释放文件句柄
  107. self.handle = nil;
  108. // 完成下载 通知 block
  109. if (error) {
  110. [self completFailueWithError:error];
  111. } else {
  112. [self completCusesseWithCode:1];
  113. }
  114. }
  115. - (void)configCallBacksWithDidReceiveResponse:(mixReceiveResponseOperation)didReceiveResponse
  116. didReceivData:(mixReceivDataOperation)didReceivData
  117. didComplete:(mixCompleteOperation)didComplete {
  118. _didReceiveResponseCallBack = didReceiveResponse;
  119. _didReceivDataCallBack = didReceivData;
  120. _didCompleteCallBack = didComplete;
  121. }
  122. #pragma mark - operations
  123. /** 成功回调 1代表下载后成功回调 2代表直接从磁盘中获取了 */
  124. - (void)completCusesseWithCode:(NSInteger)code {
  125. // 获取下载信息
  126. NSDictionary *dict = [self downLoadInfoWithFinished:YES];
  127. // 通知
  128. [[NSNotificationCenter defaultCenter] postNotificationName:mixDownloadCompleteNoti object:self userInfo:dict];
  129. if (code == 1) {
  130. // 存储 文件下载信息
  131. HLog(@"%zd", DownloadStateCompleted);
  132. _downloadState = DownloadStateCompleted;
  133. self.timeStamp = [iTools getNowTimeStamp];
  134. [mixDownloadCacheManager saveFileInfoWithDict:dict];
  135. }
  136. // 回到主线程 回调
  137. if (_didCompleteCallBack) {
  138. dispatch_async(dispatch_get_main_queue(), ^{
  139. self->_didCompleteCallBack(dict,nil);
  140. });
  141. }
  142. // 成功通知
  143. [self operationSuccessWithOperation:self];
  144. }
  145. /** 失败回调 */
  146. - (void)completFailueWithError:(NSError *)error {
  147. // 发通知
  148. [[NSNotificationCenter defaultCenter] postNotificationName:mixDownloadCompleteNoti object:self userInfo:@{@"error":error}];
  149. // 存储
  150. _downloadState = DownloadStateFailed;
  151. [mixDownloadCacheManager saveFileInfoWithDict:[self downLoadInfoWithFinished:NO]];
  152. // 回调
  153. if (_didCompleteCallBack) {
  154. dispatch_async(dispatch_get_main_queue(), ^{
  155. self->_didCompleteCallBack(nil,error);
  156. });
  157. }
  158. // 失败通知
  159. [self operationFailedWithOperation:self];
  160. }
  161. #pragma mark 发送通知
  162. // 失败某一个operation 保存本地 通知外界
  163. - (void)operationFailedWithOperation:(mixDownloadOperation *)operation {
  164. HLog(@"SGDownloadTaskExeError");
  165. operation.downloadState = DownloadStateFailed;
  166. [mixDownloadCacheManager saveFileInfoWithDict:[operation downLoadInfoWithFinished:NO]];
  167. [[NSNotificationCenter defaultCenter] postNotificationName:mixDownloadTaskExeError object:nil userInfo:@{@"operation" : operation}];
  168. }
  169. // 重启某一个operation 保存本地 通知外界
  170. - (void)operationDoningWithOperation:(mixDownloadOperation *)operation {
  171. HLog(@"SGDownloadTaskExeing");
  172. // operation.downloadState = DownloadStateDoing; // 暂停之后 数据回来 状态会被修改为下载中 不科学
  173. [mixDownloadCacheManager saveFileInfoWithDict:[operation downLoadInfoWithFinished:NO]];
  174. [[NSNotificationCenter defaultCenter] postNotificationName:mixDownloadTaskExeing object:nil userInfo:@{@"operation" : operation}];
  175. }
  176. // 等待某一个operation 保存本地 通知外界
  177. - (void)operationSuccessWithOperation:(mixDownloadOperation *)operation {
  178. HLog(@"SGDownloadTaskExeEnd");
  179. operation.downloadState = DownloadStateCompleted;
  180. [mixDownloadCacheManager saveFileInfoWithDict:[operation downLoadInfoWithFinished:YES]];
  181. [[NSNotificationCenter defaultCenter] postNotificationName:mixDownloadTaskExeEnd object:nil userInfo:@{@"operation" : operation}];
  182. }
  183. #pragma mark - get download info
  184. // 构造回调信息
  185. - (NSDictionary *)downLoadInfoWithFinished:(BOOL)finished {
  186. HLog(@"downloadState:%zd", self.downloadState);
  187. return @{
  188. @"url" : self.url,
  189. @"fileName" : self.fileName,
  190. @"fullPath" : self.fullPath,
  191. @"currentSize" : @(self.currentSize),
  192. @"totalSize" : @(self.totalSize),
  193. @"fileType" : @(self.fileType),
  194. @"timeStamp" : @(self.timeStamp),
  195. @"downloadState" : @(self.downloadState),
  196. @"isFinished" : @(finished)
  197. };
  198. }
  199. @end