nasMixUploadManager.m 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. //
  2. // nasMixUploadManager.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2024/8/27.
  6. //
  7. #import "nasMixUploadManager.h"
  8. #import "customUploadOperation.h"
  9. #import "nasUploadFileManager.h"
  10. #import "frpFileExistModel.h"
  11. #import "frpUploadModel.h"
  12. #define Kboundary2 @"Boundaryhxd"
  13. @interface nasMixUploadManager ()<NSURLSessionDataDelegate>
  14. //排队等候下载的上传地址数组
  15. @property(nonatomic,strong) NSMutableArray *uploadWaitingUrlArr;
  16. //正在下载的上传地址数组
  17. @property(nonatomic,strong) NSMutableArray *uploadingOperationArr;
  18. @property(nonatomic,strong)NSLock *arrayLock;//数组遍历是修改会挂掉
  19. @end
  20. @implementation nasMixUploadManager
  21. + (instancetype)shareManager {
  22. static nasMixUploadManager *_instance;
  23. static dispatch_once_t onceToken;
  24. dispatch_once(&onceToken, ^{
  25. _instance = [[self alloc] init];
  26. });
  27. return _instance;
  28. }
  29. - (instancetype)init {
  30. if (self = [super init]) {
  31. _maxUploadLoadCount = 2;
  32. _arrayLock = [NSLock new];
  33. //[self registeNotification];
  34. }
  35. return self;
  36. }
  37. /** 添加要上传的 模型 */
  38. - (void)addUploadWithModels:(NSArray *)fileModels{
  39. HLog(@"添加任务-- %ld",fileModels.count)
  40. for (uploadFileDataModel *model in fileModels) {
  41. BOOL needAddType = YES;
  42. //1. 排查上传中
  43. for (customUploadOperation *operationDoing in self.uploadingOperationArr) {
  44. if([operationDoing.fileModel.filename isEqualToString:model.filename]){
  45. needAddType = NO;
  46. break;
  47. }
  48. }
  49. //1. 排查等待下载
  50. for (uploadFileDataModel *waitModel in self.uploadWaitingUrlArr) {
  51. if([waitModel.filename isEqualToString:model.filename]){
  52. needAddType = NO;
  53. break;
  54. }
  55. }
  56. if(needAddType){
  57. [self.uploadWaitingUrlArr addObject:model];
  58. }
  59. }
  60. //启动上传
  61. [self beginUploadAfterDeleteOperationBy:nil];
  62. }
  63. //在添加XX后 启动下载
  64. - (void)beginUploadAfterDeleteOperationBy:(customUploadOperation*)operation
  65. {
  66. HLog(@"beginUploadAfterDeleteOperationBy")
  67. BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)];
  68. if(!isCanUseCellular){//不允许流量上传
  69. //
  70. if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){
  71. mainBlock(^{
  72. [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileSuspendAllNotification object:nil];
  73. [[iToast makeText:NSLocalizedString(@"File_Transfer_By_Cellular_tip",nil)] show];
  74. });
  75. return;
  76. }
  77. }
  78. if(ksharedAppDelegate.DisabledFileTransferType){
  79. if(ksharedAppDelegate.isImageNewFor130){
  80. [[iToast makeText:NSLocalizedString(@"File_Transfer_Disable_tip",nil)] show];
  81. }
  82. else{
  83. [[iToast makeText:NSLocalizedString(@"File_Transfer_Disable_tip2",nil)] show];
  84. }
  85. return;
  86. }
  87. if(operation){
  88. HLog(@"删除完成的上传任务")
  89. [_arrayLock lock];
  90. [self.uploadingOperationArr removeObject:operation];
  91. [_arrayLock unlock];
  92. }
  93. if(self.uploadingOperationArr.count == _maxUploadLoadCount){
  94. HLog(@"正在上传的数量达到了最大值 %ld",_maxUploadLoadCount)
  95. return;
  96. }
  97. if(self.uploadWaitingUrlArr.count == 0){
  98. HLog(@"没有等待中的上传任务")
  99. return;
  100. }
  101. NSInteger canAddTaskNumber = _maxUploadLoadCount - self.uploadingOperationArr.count;
  102. //新添加的任务
  103. NSMutableArray *newTaskArr = [NSMutableArray new];
  104. [_arrayLock lock];
  105. for (int i=0; i<canAddTaskNumber; i++) {
  106. if(self.uploadWaitingUrlArr.count >= 1){
  107. //创建上传任务
  108. uploadFileDataModel *WaitingModel = self.uploadWaitingUrlArr.firstObject;
  109. customUploadOperation * operation = [customUploadOperation new];
  110. operation.fileModel = WaitingModel;
  111. //等待下载中的任务
  112. [self.uploadWaitingUrlArr removeObjectAtIndex:0];
  113. HLog(@"添加一个新的上传任务 %@",self.uploadingOperationArr)
  114. //添加到下载中数组
  115. [self.uploadingOperationArr addObject:operation];
  116. //[self checkFileUploadStateWithOperation:operation];
  117. [newTaskArr addObject:operation];
  118. //[weakSelf handleTaskDidUploadWith:operation withState:state];
  119. }
  120. }
  121. //开始检测新的上传任务
  122. for (customUploadOperation * operation in newTaskArr) {
  123. [self checkFileUploadStateWithOperation:operation];
  124. }
  125. [newTaskArr removeAllObjects];
  126. [_arrayLock unlock];
  127. }
  128. #pragma mark 检测文件是否上传过了
  129. - (void)checkFileUploadStateWithOperation:(customUploadOperation*)operation
  130. {
  131. NSMutableDictionary*paraDict = [NSMutableDictionary new];
  132. if(operation.fileModel.savePath){
  133. NSString *absPath = [[NSString alloc] initWithFormat:@"%@%@",operation.fileModel.savePath,operation.fileModel.filename];
  134. [paraDict setValue:absPath forKey:@"absPath"];
  135. NSNumber *totalBytesNumber = [NSNumber numberWithLong:operation.fileModel.totalBytes];
  136. [paraDict setValue:totalBytesNumber forKey:@"fileSize"];
  137. }
  138. KWeakSelf
  139. [[netWorkManager shareInstance] cloudPhoneGETCallBackCode:@"isFileExist" Parameters:paraDict success:^(id _Nonnull responseObject) {
  140. frpFileExistModel *model = [[frpFileExistModel alloc] initWithDictionary:responseObject error:nil];
  141. if(model && model.status == 0){
  142. [weakSelf checkFileUploadStateFunAfterNetWith:model WithOperation:operation];
  143. }
  144. else{
  145. HLog(@"isFileExist接口异常:%@",responseObject)
  146. [weakSelf handleUploadFailOneFileBy:operation];
  147. }
  148. } failure:^(NSError * _Nonnull error) {
  149. HLog(@"%@",error)
  150. [weakSelf handleUploadFailOneFileBy:operation];
  151. }];
  152. }
  153. #pragma mark 检测分家是否存在后处理 是否要上传
  154. - (void)checkFileUploadStateFunAfterNetWith:(frpFileExistModel*)model WithOperation:(customUploadOperation*)operation
  155. {
  156. if(!model){
  157. [self handleUploadFailOneFileBy:operation];
  158. return;
  159. }
  160. operation.fileModel.didUploadBytes = 0;
  161. operation.fileModel.taskId = model.data.fileTaskId;
  162. if(!model.data.exist){//未上传过
  163. [self prepareToUploadFileWithOperation:operation];
  164. }
  165. else if(model.data.isComplete){//上传过了 并且文件上传完了
  166. //判断下文件创建长度是否一致 一致则是上传完了 不一致 重新上传一个 可能是同名的文件而已
  167. if(model.data.size >= operation.fileModel.totalBytes){//上传完了
  168. [self handleFileDidUploadFunWithOperation:operation];
  169. }
  170. else{//未上传完 isComplete 这个字段有问题
  171. operation.fileModel.didUploadBytes = model.data.size;
  172. [self prepareToUploadFileWithOperation:operation];
  173. }
  174. }
  175. else{//上传过了 未上传完成
  176. operation.fileModel.didUploadBytes = model.data.size;
  177. [self prepareToUploadFileWithOperation:operation];
  178. }
  179. }
  180. #pragma mark 任务上传过了了
  181. - (void)handleFileDidUploadFunWithOperation:(customUploadOperation*)operation
  182. {
  183. mainBlock(^{
  184. [[iToast makeText:NSLocalizedString(@"File_upload_file_already_exists",nil)] show];
  185. });
  186. NSMutableArray *delArr = [NSMutableArray new];
  187. [delArr addObject:operation.fileModel];
  188. [[nasUploadFileManager shareInstance] deleteUploadFileRecordBy:delArr withDelCache:YES complete:^(BOOL isSuccess) {
  189. if (isSuccess) {
  190. }
  191. }];
  192. }
  193. #pragma mark 准备上传文件
  194. - (void)prepareToUploadFileWithOperation:(customUploadOperation*)operation
  195. {
  196. NSMutableDictionary *paraDict = [NSMutableDictionary new];
  197. NSString* taskUid = operation.fileModel.taskId;
  198. if(!taskUid || taskUid.length == 0){
  199. taskUid = [iTools getTaskUidStr];
  200. operation.fileModel.taskId = taskUid;
  201. }
  202. [paraDict setObject:taskUid forKey:@"taskId"];
  203. [paraDict setObject:@0 forKey:@"position"];
  204. [paraDict setObject:@"true" forKey:@"isLast"];
  205. if(operation.fileModel.savePath){
  206. [paraDict setObject:operation.fileModel.savePath forKey:@"savePath"];
  207. }
  208. else{
  209. HLog(@"获取保存路径失败")
  210. [self handleUploadFailOneFileBy:operation];
  211. return;
  212. }
  213. if(operation.fileModel.filename){
  214. [paraDict setObject:operation.fileModel.filename forKey:@"filename"];
  215. }
  216. else{
  217. HLog(@"获取用户名失败")
  218. return;
  219. }
  220. KWeakSelf
  221. if(operation.fileModel.curUploadFileType == uploadFileTypeImage){
  222. [paraDict setObject:@1 forKey:@"imageType"];
  223. if(!operation.fileModel.imageData){
  224. NSString*pathStr = [cachesFileManager getFilePathWithName:operation.fileModel.filename type:operation.fileModel.curUploadFileType];
  225. NSData *imageData = [NSData dataWithContentsOfFile:pathStr];
  226. //修复出现过 图片数据小于totalBytes
  227. if(imageData){
  228. long curDataLengt = [imageData length];
  229. if(curDataLengt == operation.fileModel.didUploadBytes && curDataLengt < operation.fileModel.totalBytes){
  230. HLog(@"totalBytes 获取出错?")
  231. [self handleFileDidUploadFunWithOperation:operation];
  232. return;
  233. }
  234. }
  235. if (!imageData) {
  236. if(!operation.fileModel.asset){
  237. NSString *curLocalIdentifier = operation.fileModel.localIdentifier;
  238. PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
  239. PHAsset *asset = fetchResult.firstObject;
  240. operation.fileModel.asset = asset;
  241. }
  242. [[PHImageManager defaultManager] requestImageDataForAsset:operation.fileModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
  243. // 直接得到最终的 NSData 数据
  244. if (imageData) {
  245. operation.fileModel.imageData = imageData;
  246. if(operation.fileModel.totalBytes == 0){
  247. operation.fileModel.totalBytes = [imageData length];
  248. }
  249. [weakSelf afterGetImageDataFunWithOperation:operation];
  250. }
  251. else{
  252. HLog(@"\n\n\n\nrequestImageDataForAsset fail imageData nil\n\n\n")
  253. [weakSelf handleUploadFailOneFileBy:operation];
  254. }
  255. }];
  256. return;
  257. }
  258. operation.fileModel.imageData = imageData;
  259. }
  260. NSData *curData = operation.fileModel.imageData;
  261. operation.onceDataLengt = [curData length];
  262. if(operation.fileModel.totalBytes == 0){//异常处理
  263. operation.fileModel.totalBytes = operation.onceDataLengt;
  264. }
  265. [self startUpload:paraDict operation:operation data:curData success:^(id _Nonnull responseObject) {
  266. frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
  267. if(model && model.position == operation.fileModel.totalBytes){
  268. HLog(@"%@上传完成 000",operation.fileModel.filename)
  269. [weakSelf handleUploadDoneOneFileBy:operation];
  270. }
  271. else{
  272. HLog(@"%@上传完成异常 %ld---%ld",operation.fileModel.filename,model.position,operation.fileModel.totalBytes)
  273. [weakSelf handleUploadDoneOneFileBy:operation];
  274. }
  275. } faild:^(NSError * _Nonnull error) {
  276. HLog(@"%@上传失败",operation.fileModel.filename)
  277. [weakSelf handleUploadFailOneFileBy:operation];
  278. }];
  279. }
  280. else{
  281. [paraDict setObject:@1 forKey:@"videoType"];
  282. [paraDict setObject:@"false" forKey:@"isLast"];
  283. if(![cachesFileManager checkFileIsSaveState:operation.fileModel.filename withType:uploadFileTypeVideo]){
  284. if(!operation.fileModel.asset){
  285. NSString *curLocalIdentifier = operation.fileModel.localIdentifier;
  286. PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
  287. PHAsset *asset = fetchResult.firstObject;
  288. operation.fileModel.asset = asset;
  289. }
  290. //真正的视频数据
  291. PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  292. options.version = PHVideoRequestOptionsVersionOriginal;
  293. [[PHImageManager defaultManager] requestAVAssetForVideo:operation.fileModel.asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
  294. if ([asset isKindOfClass:[AVURLAsset class]]) {
  295. AVURLAsset* urlAsset = (AVURLAsset*)asset;
  296. BOOL isSuc = [cachesFileManager copyVideoItemAtPath:[urlAsset.URL path] fileName:operation.fileModel.filename error:nil];
  297. if (isSuc) {
  298. [weakSelf afterGetVideoDataFunWithOperation:operation];
  299. }
  300. else{
  301. [weakSelf handleUploadFailOneFileBy:operation];
  302. }
  303. }
  304. else{
  305. [weakSelf handleUploadFailOneFileBy:operation];
  306. }
  307. }];
  308. return;
  309. }
  310. long curPosition = operation.fileModel.didUploadBytes;
  311. [self beginUploadVideoDataFunBy:operation with:curPosition withPara:paraDict success:^(id _Nonnull responseObject) {
  312. } faild:^(NSError * _Nonnull error) {
  313. }];
  314. }
  315. }
  316. #pragma mark 视频上传
  317. - (void)beginUploadVideoDataFunBy:(customUploadOperation*)operation with:(NSInteger)position withPara:(NSMutableDictionary*)paraDict success:(netWork_Success)success faild:(netWork_Faild)faildStr
  318. {
  319. if(operation.isCancelType){
  320. HLog(@"防止取消不了任务生效")
  321. return;
  322. }
  323. BOOL isLastPicece = NO;
  324. if((operation.fileModel.totalBytes - position) <= MaxNasUploadPieceSzie){
  325. [paraDict setObject:@"true" forKey:@"isLast"];
  326. isLastPicece = YES;
  327. }
  328. else{
  329. [paraDict setObject:@"false" forKey:@"isLast"];
  330. }
  331. [paraDict setObject:[NSNumber numberWithLong:position] forKey:@"position"];
  332. //视频数据切片
  333. __block NSData *videoData = [self cutVideoFileFunAtIndex:position withMaxLenght:MaxNasUploadPieceSzie withModel:operation.fileModel];
  334. if(!videoData ||videoData.length ==0){
  335. HLog(@"视频没获取到")
  336. [self handleUploadFailOneFileBy:operation];
  337. return;
  338. }
  339. operation.onceDataLengt = [videoData length];
  340. KWeakSelf
  341. [self startUpload:paraDict operation:operation data:videoData success:^(id _Nonnull responseObject) {
  342. frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
  343. if(model && model.position >= operation.fileModel.totalBytes){
  344. HLog(@"%@上传完成 001",operation.fileModel.filename)
  345. [weakSelf handleUploadDoneOneFileBy:operation];
  346. }
  347. else{
  348. HLog(@"%@上传完成一片 %ld",operation.fileModel.filename,model.position)
  349. [weakSelf beginUploadVideoDataFunBy:operation with:model.position withPara:paraDict success:^(id _Nonnull responseObject) {
  350. success(responseObject);
  351. } faild:^(NSError * _Nonnull error) {
  352. NSError *err = error;
  353. if(error.code != -999){
  354. faildStr(err);
  355. }
  356. }];
  357. }
  358. } faild:^(NSError * _Nonnull error) {
  359. HLog(@"%@上传失败",operation.fileModel.filename)
  360. [weakSelf handleUploadFailOneFileBy:operation];
  361. }];
  362. }
  363. #pragma mark 分段读视频文件
  364. -(NSData*)cutVideoFileFunAtIndex:(NSUInteger)dataIndex withMaxLenght:(NSInteger)maxLengt withModel:(uploadFileDataModel*)dataModel{
  365. HLog(@"视频切片开始 线程:%@",[NSThread currentThread]);
  366. NSString *filePath = [cachesFileManager getFilePathWithName:dataModel.filename type:uploadFileTypeVideo]; // 文件路径
  367. NSFileManager *manager0 = [NSFileManager defaultManager];
  368. if(![manager0 fileExistsAtPath:filePath]) {
  369. return [NSData new];
  370. }
  371. NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; // 创建文件句柄
  372. // 设置分段读取的大小,这里以每次读取1KB为例
  373. const NSUInteger chunkSize = maxLengt;//cutVideoPieceSzie;//5 * 1024 *1024;
  374. NSMutableData *data = [NSMutableData data];
  375. if (fileHandle) {
  376. long long endOfFile = [fileHandle seekToEndOfFile];
  377. if(dataModel.totalBytes == 0
  378. || dataModel.totalBytes < endOfFile){//异常处理
  379. dataModel.totalBytes = endOfFile;
  380. }
  381. //异常处理
  382. if(endOfFile == dataIndex){
  383. dataModel.totalBytes = endOfFile;
  384. dataModel.didUploadBytes = endOfFile;
  385. dataModel.curUploadStateType = uploadStateDone;
  386. [fileHandle closeFile];
  387. return data;
  388. }
  389. if (endOfFile >= chunkSize) {
  390. // 读取文件的分段数据到某个位置
  391. [fileHandle seekToFileOffset:dataIndex];
  392. // 读取文件的分段数据
  393. NSData* chunk = [fileHandle readDataOfLength:chunkSize];
  394. if (chunk) {
  395. [data appendData:chunk];
  396. }
  397. }
  398. else{
  399. // 读取文件的分段数据到某个位置
  400. [fileHandle seekToFileOffset:dataIndex];
  401. [data appendData:[fileHandle readDataToEndOfFile]];
  402. }
  403. // 在这里可以对文件内容进行处理
  404. // ...
  405. // 关闭文件句柄
  406. [fileHandle closeFile];
  407. }
  408. HLog(@"视频切片完成 dataIndex:%ld --长度:%ld",dataIndex,[data length])
  409. return data;
  410. }
  411. #pragma mark 处理上传完成
  412. - (void)handleUploadDoneOneFileBy:(customUploadOperation*)operation
  413. {
  414. HLog(@"handleUploadDoneOneFileBy")
  415. [[NSNotificationCenter defaultCenter] postNotificationName:nasUploadTaskExeEnd object:operation.fileModel];
  416. [self beginUploadAfterDeleteOperationBy:operation];
  417. }
  418. #pragma mark 处理删除失败
  419. - (void)handleUploadFailOneFileBy:(customUploadOperation*)operation
  420. {
  421. operation.fileModel.curUploadStateType = uploadStateFail;
  422. [[NSNotificationCenter defaultCenter] postNotificationName:nasUploadTaskExeError object:operation.fileModel];
  423. [self beginUploadAfterDeleteOperationBy:operation];
  424. }
  425. #pragma mark 根据 asset 获取到图片数据
  426. - (void)afterGetImageDataFunWithOperation:(customUploadOperation*)operation
  427. {
  428. [cachesFileManager getFileNameWithContent:operation.fileModel.imageData fileName:operation.fileModel.filename type:uploadFileTypeImage];
  429. [self prepareToUploadFileWithOperation:operation];
  430. }
  431. #pragma mark 根据 asset 获取到视频数据
  432. - (void)afterGetVideoDataFunWithOperation:(customUploadOperation*)operation
  433. {
  434. [self prepareToUploadFileWithOperation:operation];
  435. }
  436. #pragma mark 开始上传
  437. - (void)startUpload:(NSMutableDictionary *)params operation:(customUploadOperation*)operation data:(NSData *)data success:(netWork_Success)success faild:(netWork_Faild)faildStr {
  438. NSString *urlString = ksharedAppDelegate.NASFileByBoxService;
  439. urlString = [[NSString alloc] initWithFormat:@"%@uploadFile",urlString];
  440. NSURL *URL = [NSURL URLWithString:urlString];
  441. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  442. [request setHTTPMethod:@"POST"];
  443. //请求体
  444. NSMutableData *bodyData = [self getBodyDataWithRequest:request withModel:operation.fileModel withData:data withPara:params];
  445. //设置请求体
  446. [request setHTTPMethod:@"POST"];
  447. [request setHTTPBody:bodyData];
  448. //设置请求体长度
  449. NSInteger length = [bodyData length];
  450. [request setValue:[NSString stringWithFormat:@"%ld",length] forHTTPHeaderField:@"Content-Length"];
  451. //设置 POST请求文件上传
  452. [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary2] forHTTPHeaderField:@"Content-Type"];
  453. KWeakSelf
  454. //回话对象
  455. NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
  456. operation.session = session;
  457. //请求task
  458. /*
  459. 第一个参数:请求对象
  460. 第二个参数:传递是要上传的数据(请求体)
  461. 第三个参数:
  462. */
  463. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:nil completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  464. //解析
  465. [weakSelf handleCustomUploadResultBy:data withResponse:response withError:error success:success faild:faildStr];
  466. }];
  467. // NSString *filePath = [cachesFileManager getFilePathWithName:dataModel.filename type:uploadFileTypeVideo]; // 文件路径
  468. // NSURL *filePathUrl = [NSURL URLWithString:filePath];
  469. //
  470. // NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:filePathUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  471. // HLog(@"data string:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
  472. //[weakSelf handleCustomUploadResultBy:data withResponse:response withError:error];
  473. // }];
  474. // NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  475. //
  476. // HLog(@"data string:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
  477. //[weakSelf handleCustomUploadResultBy:data withResponse:response withError:error];
  478. //
  479. //// NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
  480. //// NSDictionary *dict = (NSDictionary *)object;
  481. //// NSLog(@"=====%@",[dict objectForKey:@"success"]);
  482. // }];
  483. //执行Task
  484. [uploadTask resume];
  485. operation.dataTask = uploadTask;
  486. }
  487. #pragma mark 用系统方法写的上传处理
  488. - (void)handleCustomUploadResultBy:(NSData*)data withResponse:(NSURLResponse*)response withError:(NSError*)error success:(netWork_Success)success faild:(netWork_Faild)faildStr{
  489. if(error){
  490. HLog(@"上传错误:%@",error)
  491. if(error.code != -999){
  492. faildStr(error);
  493. }
  494. return;
  495. }
  496. NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
  497. NSDictionary *dict = (NSDictionary *)object;
  498. frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:dict error:nil];
  499. if(model && [model.msg isEqualToString:@"success"]){
  500. success(dict);
  501. }
  502. else{
  503. NSError *err = [NSError new];
  504. faildStr(err);
  505. }
  506. }
  507. - (NSMutableData *)getBodyDataWithRequest:(NSMutableURLRequest *)request withModel:(uploadFileDataModel*)dataModel withData:(NSData*)data withPara:(NSMutableDictionary*)params{
  508. //1 边界符号要配置请求头里面去
  509. /*
  510. multipart/form-data 是表单格式
  511. charset=utf-8 是utf-8编码
  512. bounary 是表单开头
  513. */
  514. [request setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", Kboundary2] forHTTPHeaderField:@"Content-Type"];
  515. /// body
  516. NSMutableData *boydData = [NSMutableData data];
  517. // 2.1 边界符号(开始边界)
  518. //2.1.1 其它参数
  519. NSMutableString *paraString = [NSMutableString new];
  520. //[paraString appendFormat:@"--%@\r\n",Kboundary];//\n:换行 \n:切换到行首
  521. for (NSString *key in params) {
  522. NSString *value = params[key];
  523. [paraString appendFormat:@"--%@\r\n",Kboundary2];//\n:换行 \n:切换到行首
  524. [paraString appendFormat:@"Content-Disposition: form-data; name=\"%@\"",key];
  525. [paraString appendFormat:@"\r\n"];
  526. [paraString appendFormat:@"\r\n"];
  527. [paraString appendFormat:@"%@\r\n",value];
  528. }
  529. //[boydData appendData:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
  530. // body每一个段内容以换行符作为结束标示
  531. NSString *fileBeginBoundary = [NSString stringWithFormat:@"--%@\r\n", Kboundary2];
  532. //[boydData appendData:[fileBeginBoundary dataUsingEncoding:NSUTF8StringEncoding]];
  533. [paraString appendString:fileBeginBoundary];
  534. // 2.2 属性配置 名字;key;类型
  535. NSString *serverFileKey = @"image"; //key
  536. //NSString *serverFileKey = @"file";
  537. NSString *serverContentTypes = @"image/png"; //类型
  538. if (dataModel.curUploadFileType == uploadFileTypeVideo) {
  539. serverFileKey = @"video";
  540. serverContentTypes = @"video/mp4";
  541. }
  542. NSString *serverFileName = dataModel.filename; //name
  543. // filename已命名文件; name相当于一个key, 这个名字和服务器保持一致
  544. /*
  545. 理解key,表单发送给服务端,服务端拿到数据之后,可以将任务解析成一个字典了imageDict;图片数据会通过这个字典里面的name来获取图片(伪代码 image = imageDict[serverFileKey])
  546. */
  547. //2.3 拼接数据(创建一个字符串来拼装)
  548. NSMutableString *string = [NSMutableString new];
  549. [string appendFormat:@"Content-Disposition:form-data; name=\"%@\"; filename=\"%@\" ", @"file", serverFileName];
  550. //[string appendFormat:@"%@", KNewLine];
  551. [string appendFormat:@"\r\n"];
  552. [string appendFormat:@"Content-Type:%@", serverContentTypes];
  553. // [string appendFormat:@"%@", KNewLine];
  554. // [string appendFormat:@"%@", KNewLine];
  555. [string appendFormat:@"\r\n"];
  556. [string appendFormat:@"\r\n"];
  557. // [boydData appendData:[string dataUsingEncoding:NSUTF8StringEncoding]];
  558. [paraString appendString:string];
  559. [boydData appendData:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
  560. // 2.3 拼接数据(拼接文件数据)
  561. [boydData appendData:data];
  562. // 2.4 边界符号 (结束边界)
  563. NSString *fileEndBoundary = [NSString stringWithFormat:@"\r\n--%@--", Kboundary2];
  564. [boydData appendData:[fileEndBoundary dataUsingEncoding:NSUTF8StringEncoding]];
  565. return boydData;
  566. }
  567. #pragma mark 上传的文件已存在
  568. - (void)handleTaskDidUploadWith:(customUploadOperation*)operation withState:(NSInteger)state
  569. {
  570. if(state == 1){
  571. [[iToast makeText:NSLocalizedString(@"File_upload_file_already_exists",nil)] show];
  572. }
  573. HLog(@"上传的文件已存在 删除任务:_uploadingOperationArr:%@",_uploadingOperationArr);
  574. [self.uploadingOperationArr removeObject:operation];
  575. NSMutableArray *delArr = [NSMutableArray new];
  576. [delArr addObject:operation.fileModel];
  577. [[nasUploadFileManager shareInstance] deleteUploadFileRecordBy:delArr withDelCache:NO complete:^(BOOL isSuccess) {
  578. if (isSuccess) {
  579. }
  580. }];
  581. [self beginUploadAfterDeleteOperationBy:nil];
  582. }
  583. #pragma mark - <NSURLSessionDataDelegate>
  584. // ssl 服务 证书信任
  585. - (void)URLSession:(NSURLSession *)session
  586. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  587. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
  588. if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
  589. return;
  590. }
  591. // 信任该插件
  592. NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
  593. // 第一个参数 告诉系统如何处置
  594. completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
  595. }
  596. //当请求协议是https的时候回调用该方法
  597. //Challenge 挑战 质询(受保护空间)
  598. //NSURLAuthenticationMethodServerTrust 服务器信任证书
  599. - (void)URLSession:(NSURLSession *)session
  600. task:(NSURLSessionTask *)task
  601. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  602. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler {
  603. if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
  604. return;
  605. }
  606. // 信任该插件
  607. NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
  608. // 第一个参数 告诉系统如何处置
  609. completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
  610. }
  611. // 接受到响应调用
  612. - (void)URLSession:(NSURLSession *)session
  613. dataTask:(NSURLSessionDataTask *)dataTask
  614. didReceiveResponse:(NSURLResponse *)response
  615. completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
  616. completionHandler(NSURLSessionResponseAllow);
  617. }
  618. // 上传进度
  619. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
  620. //每包发送的大小bytesSent,totalBytesSent已经上传了多少;totalBytesExpectedToSend总共要发送多少
  621. // 32768 = 32KB
  622. HLog(@"didSendBodyData: %lld--%lld-%lld", bytesSent, totalBytesSent, totalBytesExpectedToSend);
  623. [_arrayLock lock];
  624. for (customUploadOperation*operation in _uploadingOperationArr) {
  625. HLog(@"正在遍历数组 _uploadingOperationArr:%@",_uploadingOperationArr);
  626. if(operation.dataTask == task){
  627. operation.fileModel.didUploadBytes += bytesSent;
  628. //调整下大小 因为上传的数据 除了data 长度 还包含了 参数大小
  629. if(totalBytesSent == totalBytesExpectedToSend){
  630. operation.fileModel.didUploadBytes -= (totalBytesExpectedToSend - operation.onceDataLengt);
  631. }
  632. NSTimeInterval curTime = [[NSDate date] timeIntervalSince1970];
  633. NSTimeInterval timeDiff = curTime - operation.preNotTimeInterval;
  634. //HLog(@"控制刷新时间为1秒:%f",timeDiff);
  635. if (operation.preNotTimeInterval <= 0
  636. || timeDiff > 0.8 ) {
  637. operation.preNotTimeInterval = curTime;
  638. [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileUploadingNotification object:operation.fileModel];
  639. }
  640. break;
  641. }
  642. }
  643. [_arrayLock unlock];
  644. }
  645. #pragma mark 取消单个任务
  646. - (void)cancelUploadTaskFunWith:(uploadFileDataModel*)fileModel
  647. {
  648. HLog(@"取消任务-- %@--%@",fileModel.filename,fileModel.taskId)
  649. [_arrayLock lock];
  650. for (customUploadOperation*operation in _uploadingOperationArr) {
  651. HLog(@"正在遍历数组 _uploadingOperationArr:%@",_uploadingOperationArr);
  652. if([operation.fileModel.filename isEqualToString:fileModel.filename]){
  653. operation.isCancelType = YES;
  654. [operation.dataTask cancel];
  655. [_arrayLock unlock];
  656. [self beginUploadAfterDeleteOperationBy:operation];
  657. return;
  658. }
  659. }
  660. for (uploadFileDataModel*waitModel in _uploadWaitingUrlArr) {
  661. if([waitModel.filename isEqualToString:fileModel.filename]){
  662. [_uploadWaitingUrlArr removeObject:waitModel];
  663. [_arrayLock lock];
  664. [self beginUploadAfterDeleteOperationBy:nil];
  665. return;
  666. }
  667. }
  668. [_arrayLock unlock];
  669. }
  670. #pragma mark 取消所有任务
  671. - (void)cancelUploadAllTaskFun
  672. {
  673. HLog(@"取消所有任务")
  674. [_arrayLock lock];
  675. [_uploadWaitingUrlArr removeAllObjects];
  676. for (customUploadOperation*operation in _uploadingOperationArr) {
  677. HLog(@"正在遍历数组 _uploadingOperationArr:%@",_uploadingOperationArr);
  678. operation.isCancelType = YES;
  679. [operation.dataTask cancel];
  680. }
  681. [_uploadingOperationArr removeAllObjects];
  682. [_arrayLock unlock];
  683. }
  684. #pragma mark 判断是否在上传中
  685. - (BOOL)checkUploadTaskDoingFun
  686. {
  687. if(_uploadWaitingUrlArr.count >0 || _uploadingOperationArr.count>0){
  688. return YES;
  689. }
  690. return NO;
  691. }
  692. #pragma mark - lazy load
  693. - (NSMutableArray *)uploadWaitingUrlArr {
  694. if (!_uploadWaitingUrlArr) {
  695. _uploadWaitingUrlArr = [NSMutableArray array];
  696. }
  697. return _uploadWaitingUrlArr;
  698. }
  699. - (NSMutableArray *)uploadingOperationArr {
  700. if (!_uploadingOperationArr) {
  701. _uploadingOperationArr = [NSMutableArray array];
  702. }
  703. return _uploadingOperationArr;
  704. }
  705. @end