// // uploadFileManager.m // 隐私保护 // // Created by xd h on 2023/11/15. // #import "uploadFileManager.h" #import @implementation uploadFileManager static uploadFileManager * cur_uploadFileShareInstance = nil; +(uploadFileManager *)shareInstance; { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ cur_uploadFileShareInstance = [[uploadFileManager alloc] init]; }); return cur_uploadFileShareInstance; } - (id)init { self = [super init]; if (self) { //[self initManager]; } return self; } #pragma mark 读取数据库数据 - (void)getDataInDatabaseFun:(BOOL)isReGet complete:(custom_complete_Arr)complete { if(_databaseArr && _databaseArr.count == 3 && !isReGet){ complete(_databaseArr); return; } if(!_databaseArr) { _databaseArr = [NSMutableArray new]; } //KWeakSelf dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ [uploadFileDataModel bg_findAsync:upLoadFile_image_tableName limit:0 orderBy:nil desc:NO complete:^(NSArray * _Nullable array) { NSMutableArray *failArr = [NSMutableArray new]; NSMutableArray *doneArr = [NSMutableArray new]; NSMutableArray *otherArr = [NSMutableArray new]; for (uploadFileDataModel * curModel in array) { //图片 和视频 还原 if(curModel.curUploadFileType == uploadFileTypeImage){ // NSString*pathStr = [cachesFileManager getFilePathWithName:curModel.filename type:uploadFileTypeImage]; // curModel.imageData = [NSData dataWithContentsOfFile:pathStr]; } else if(curModel.curUploadFileType == uploadFileTypeVideo){ // NSString*pathStr = [cachesFileManager getFilePathWithName:curModel.videoFirstImageName type:uploadFileTypeImage]; // curModel.imageData = [NSData dataWithContentsOfFile:pathStr]; if(curModel.curUploadStateType != uploadStateDone){ //NSString*videoPathStr = [cachesFileManager getFilePathWithName:curModel.filename type:uploadFileTypeVideo]; //curModel.videoData = [NSData dataWithContentsOfFile:videoPathStr]; } } if(curModel.curUploadStateType == uploadStateFail){ [failArr addObject:curModel]; } else if(curModel.curUploadStateType == uploadStateDone){ [doneArr addObject:curModel]; } else{ [otherArr addObject:curModel]; } } NSLock *lock = [NSLock new]; [lock lock]; NSMutableArray *newArr = [NSMutableArray new]; [newArr addObject:otherArr]; [newArr addObject:doneArr]; [newArr addObject:failArr]; self->_databaseArr = newArr; [lock unlock]; complete(self->_databaseArr); }]; }); } //把TZAssetModel 转成 我们需要上传的model - (void)handlTZAssetModelToUploadFileDataFunBy:(NSMutableArray*)indexPathsForSelectedItems complete:(custom_complete_Arr)complete { if(!indexPathsForSelectedItems && indexPathsForSelectedItems.count == 0){ complete(nil); return; } if(!_fileModelDataArr){ _fileModelDataArr = [NSMutableArray new]; } self.curUploadModelNumbers = indexPathsForSelectedItems.count; NSLock *lock = [NSLock new]; for (TZAssetModel * model in indexPathsForSelectedItems) { uploadFileDataModel * curModel = [uploadFileDataModel new]; curModel.asset = model.asset; curModel.localIdentifier = model.asset.localIdentifier; BOOL isRepeatingTasksType = NO; [lock lock]; //查询上传任务是否存在 if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadingArr = [[NSMutableArray alloc] initWithArray:_databaseArr[0]]; for (uploadFileDataModel *preModel in uploadingArr) { if([preModel.localIdentifier isEqualToString:curModel.localIdentifier]){ isRepeatingTasksType = YES; break; } } } [lock unlock]; if(isRepeatingTasksType){ continue; } curModel.imageData = model.imageData; curModel.videoData = model.videoData; curModel.filename = [model.asset valueForKey:@"filename"]; curModel.curUploadStateType = uploadStateWait; if(model.type == TZAssetModelMediaTypeVideo){ curModel.curUploadFileType = uploadFileTypeVideo; [cachesFileManager getFileNameWithContent:curModel.videoData fileName:curModel.filename type:uploadFileTypeVideo]; //curModel.totalBytes = [model.videoData length]; curModel.totalBytes = model.totalBytes; curModel.videoData = [NSData new];//视频文件存储到文件后内存清空 NSString *imgName1 = [curModel.filename stringByReplacingOccurrencesOfString:@"." withString:@"_"]; curModel.videoFirstImageName = [[NSString alloc] initWithFormat:@"%@.png",imgName1]; //第一帧图片 [[PHImageManager defaultManager] requestImageDataForAsset:curModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { // 直接得到最终的 NSData 数据 if (imageData) { curModel.imageData = imageData; [cachesFileManager getFileNameWithContent:curModel.imageData fileName:curModel.videoFirstImageName type:uploadFileTypeImage];; } }]; } else{ curModel.curUploadFileType = uploadFileTypeImage; curModel.totalBytes = model.totalBytes; if(curModel.imageData) { [cachesFileManager getFileNameWithContent:curModel.imageData fileName:curModel.filename type:uploadFileTypeImage]; } else{ [[PHImageManager defaultManager] requestImageDataForAsset:curModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { // 直接得到最终的 NSData 数据 if (imageData) { curModel.imageData = imageData; [cachesFileManager getFileNameWithContent:curModel.imageData fileName:curModel.filename type:uploadFileTypeImage];; } }]; } } //[_fileModelDataArr addObject:curModel]; //保存到数据库 curModel.bg_tableName = upLoadFile_image_tableName; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ [curModel bg_saveOrUpdateAsync:^(BOOL isSuccess) { //HLog(@"%@ 写入 %@", curModel.filename, isSuccess ? @"成功":@"失败"); }]; }); } KWeakSelf [self getDataInDatabaseFun:YES complete:^(NSMutableArray * _Nonnull Arr) { complete(Arr); [weakSelf handleUploadFileModelBg_idFun:Arr]; }]; } #pragma mark 处理当前的model 加上bg_id - (void)handleUploadFileModelBg_idFun:(NSMutableArray*)totalArr { if(!totalArr || totalArr.count != 3){ return; } NSMutableArray *curArr = totalArr[0]; //for (int i=0; i<_curUploadModelNumbers; i++) NSLock *lock = [NSLock new]; [lock lock]; [_fileModelDataArr removeAllObjects]; for (int i=0; i 0 && _reUploadIngSelectIndex < _fileModelDataArr.count){ _curUploadFileDataModel = _fileModelDataArr[_reUploadIngSelectIndex]; } else { _curUploadFileDataModel = _fileModelDataArr.firstObject; } if(!_curUploadFileDataModel){ return; } if(_curUploadFileDataModel.curUploadFileType == uploadFileTypeImage){ NSString*pathStr = [cachesFileManager getFilePathWithName:_curUploadFileDataModel.filename type:_curUploadFileDataModel.curUploadFileType]; _curUploadFileDataModel.imageData = [NSData dataWithContentsOfFile:pathStr]; if(_curUploadFileDataModel.imageData && _curUploadFileDataModel.imageData.length >0){ [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileBeginNotification object:_curUploadFileDataModel]; return; } } else{ //NSString*pathStr = [cachesFileManager getFilePathWithName:_curUploadFileDataModel.filename type:uploadFileTypeVideo]; if([cachesFileManager checkFileIsSaveState:_curUploadFileDataModel.filename withType:uploadFileTypeVideo]){ [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileBeginNotification object:_curUploadFileDataModel]; return; } } if(!_curUploadFileDataModel.asset){ NSString *curLocalIdentifier = _curUploadFileDataModel.localIdentifier; PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil]; PHAsset *asset = fetchResult.firstObject; _curUploadFileDataModel.asset = asset; } if(!_curUploadFileDataModel.asset){ [self getDataWrongToChangeFailFun]; return; } KWeakSelf if(_curUploadFileDataModel.curUploadFileType == uploadFileTypeImage) { if(!_curUploadFileDataModel.imageData || _curUploadFileDataModel.imageData.length == 0){ [[PHImageManager defaultManager] requestImageDataForAsset:_curUploadFileDataModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { // 直接得到最终的 NSData 数据 if (imageData) { self->_curUploadFileDataModel.imageData = imageData; [weakSelf afterGetImageDataFun]; } else{ [weakSelf getDataWrongToChangeFailFun]; } }]; } } else if(_curUploadFileDataModel.curUploadFileType == uploadFileTypeVideo){ //第一帧图片 [[PHImageManager defaultManager] requestImageDataForAsset:_curUploadFileDataModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { // 直接得到最终的 NSData 数据 if (imageData) { self->_curUploadFileDataModel.imageData = imageData; [weakSelf afterGetImageDataInVideoFun]; } }]; //真正的视频数据 PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; options.version = PHVideoRequestOptionsVersionOriginal; [[PHImageManager defaultManager] requestAVAssetForVideo:_curUploadFileDataModel.asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) { if ([asset isKindOfClass:[AVURLAsset class]]) { AVURLAsset* urlAsset = (AVURLAsset*)asset; BOOL isSuc = [cachesFileManager copyVideoItemAtPath:[urlAsset.URL path] fileName:_curUploadFileDataModel.filename error:nil]; //NSData *videoData = [NSData dataWithContentsOfURL:urlAsset.URL]; if (isSuc) { //self->_curUploadFileDataModel.videoData = videoData; [weakSelf afterGetVideoDataFun]; } else{ [weakSelf getDataWrongToChangeFailFun]; } } }]; } } #pragma mark 获取数据失败 报错 - (void)getDataWrongToChangeFailFun { [self changeUploadFileState:uploadStateFail withDidUploadBytes:_curUploadFileDataModel.didUploadBytes withModel:_curUploadFileDataModel complete:^(BOOL isSuccess) { }]; } #pragma mark 根据 asset 获取到图片数据 - (void)afterGetImageDataFun { [cachesFileManager getFileNameWithContent:_curUploadFileDataModel.imageData fileName:_curUploadFileDataModel.filename type:uploadFileTypeImage]; [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileBeginNotification object:_curUploadFileDataModel]; } - (void)afterGetImageDataInVideoFun { [cachesFileManager getFileNameWithContent:_curUploadFileDataModel.imageData fileName:_curUploadFileDataModel.videoFirstImageName type:uploadFileTypeImage]; } - (void)afterGetVideoDataFun { [cachesFileManager getFileNameWithContent:_curUploadFileDataModel.videoData fileName:_curUploadFileDataModel.filename type:uploadFileTypeVideo]; _curUploadFileDataModel.videoData = nil; [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileBeginNotification object:_curUploadFileDataModel]; } //修改文件上传的状态 - (void)changeUploadFileState:(uploadStateType)curUploadStateType withDidUploadBytes:(long)didUpLoadBytes withModel:(uploadFileDataModel*)model complete:(custom_complete_B)complete { if(model.bg_id.integerValue == _curUploadFileDataModel.bg_id.integerValue){ _curUploadFileDataModel.curUploadStateType = curUploadStateType; _curUploadFileDataModel.didUploadBytes = didUpLoadBytes; } model.curUploadStateType = curUploadStateType; model.didUploadBytes = didUpLoadBytes; if(!_isSuspendType || curUploadStateType == uploadStateSuspend){ [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileRefreshNotification object:model]; } if(curUploadStateType == uploadStateUploading){ return; } //NSNumber * numberUploadState = nil; NSString* where = nil; // if(curUploadStateType == uploadStateDone) // {//只有上传中的才可能是完成的 // numberUploadState = [NSNumber numberWithInt:uploadStateUploading]; // where = [NSString stringWithFormat:@"where %@=%@ and %@=%@ ",bg_sqlKey(@"filename"),bg_sqlValue(_curUploadFileDataModel.filename),bg_sqlKey(@"curUploadStateType"),bg_sqlValue(numberUploadState)]; // } // else // {//查找非上传完成的 // numberUploadState = [NSNumber numberWithInt:uploadStateDone]; // where = [NSString stringWithFormat:@"where %@=%@ and %@!=%@ ",bg_sqlKey(@"filename"),bg_sqlValue(_curUploadFileDataModel.filename),bg_sqlKey(@"curUploadStateType"),bg_sqlValue(numberUploadState)]; // } where = [NSString stringWithFormat:@"where %@=%@ ",bg_sqlKey(@"bg_id"),bg_sqlValue(model.bg_id)]; //HLog(@"ffff:%@",_curUploadFileDataModel.bg_id); KWeakSelf dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ [uploadFileDataModel bg_findAsync:upLoadFile_image_tableName where:where complete:^(NSArray * _Nullable array) { for (uploadFileDataModel * curModel in array) { curModel.curUploadStateType = curUploadStateType; curModel.didUploadBytes = didUpLoadBytes; if(curUploadStateType == uploadStateDone){ curModel.videoData = [NSData new]; if(curModel.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:curModel.filename type:uploadFileTypeVideo error:nil]; } [weakSelf handleDatabaseArrByDelete:curModel]; [weakSelf handleDatabaseArrByInDone:curModel]; } else if(curUploadStateType == uploadStateFail){ [weakSelf handleDatabaseArrByDelete:curModel]; [weakSelf handleDatabaseArrByInFail:curModel]; } [curModel bg_saveOrUpdateAsync:^(BOOL isSuccess) { //HLog(@"%@ 写入 %@", model.filename, isSuccess ? @"成功":@"失败"); }]; } complete(YES); }]; }); } - (void)handleDatabaseArrByDelete:(uploadFileDataModel*)delModel { if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadingArr = _databaseArr[0]; for (uploadFileDataModel *baseUploadFileDataMod in uploadingArr) { if(delModel.bg_id.integerValue == baseUploadFileDataMod.bg_id.integerValue){ [uploadingArr removeObject:baseUploadFileDataMod]; break; } } } } - (void)handleDatabaseArrByInDone:(uploadFileDataModel*)uploadmodel { if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadDoneArr = _databaseArr[1]; [uploadDoneArr addObject:uploadmodel]; } } - (void)handleDatabaseArrByInFail:(uploadFileDataModel*)uploadmodel { if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadFailArr = _databaseArr[2]; [uploadFailArr addObject:uploadmodel]; } } //暂停上传完成 - (void)suspendUploadFileFun:(BOOL)isSuspendAll { // if(isSuspendAll){ // // } if(!_fileModelDataArr || !_curUploadFileDataModel){ return; } _isSuspendType = YES; _isUploadIngType = NO; [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileSuspendNotification object:nil]; NSEnumerator *curArr = [_fileModelDataArr reverseObjectEnumerator]; for (uploadFileDataModel*model in curArr) { [self changeUploadFileState:uploadStateSuspend withDidUploadBytes:model.didUploadBytes withModel:model complete:^(BOOL isSuccess) { }]; } } //某个文件重新上传 - (void)reUploadFileFunBy:(NSMutableArray*)Arr { if(!_fileModelDataArr){ _fileModelDataArr = [NSMutableArray new]; } _reUploadIngSelectIndex = 0; for (uploadFileDataModel*addModel in Arr) { BOOL needAddModel = YES; //for (uploadFileDataModel*preModel in _fileModelDataArr) for (int i=0;i< _fileModelDataArr.count;i++) { uploadFileDataModel*preModel = _fileModelDataArr[i]; if(addModel.bg_id.integerValue == preModel.bg_id.integerValue || [addModel.localIdentifier isEqualToString:preModel.localIdentifier]) { needAddModel = NO; if(_reUploadIngSelectIndex == 0){ _reUploadIngSelectIndex = i; if(i==0){ _reUploadIngSelectIndex = -1; } } break; } } if(needAddModel){ [_fileModelDataArr addObject:addModel]; } } //[_fileModelDataArr addObjectsFromArray:Arr]; [self beginUploadFileFun]; } - (void)uploadFileDoneFun { long totalSizeByte = _curUploadFileDataModel.totalBytes; [self changeUploadFileState:uploadStateDone withDidUploadBytes:totalSizeByte withModel:_curUploadFileDataModel complete:^(BOOL isSuccess) { [self->_fileModelDataArr removeObject:self->_curUploadFileDataModel]; self->_isUploadIngType = NO; if(self->_fileModelDataArr.count > 0){ [self beginUploadFileFun]; } }]; } //文件上传失败 - (void)uploadFileFailFun { [self changeUploadFileState:uploadStateFail withDidUploadBytes:_curUploadFileDataModel.didUploadBytes withModel:_curUploadFileDataModel complete:^(BOOL isSuccess) { [self->_fileModelDataArr removeObject:self->_curUploadFileDataModel]; if(self->_fileModelDataArr.count > 0){ [self beginUploadFileFun]; } else{ self->_isUploadIngType = NO; } }]; mainBlock(^{ [[iToast makeText:NSLocalizedString(@"File_upload_fail",nil)] show]; }); } //删除本地数据库记录 - (void)deleteUploadFileRecordBy:(NSMutableArray *)delArr withDelCache:(BOOL)isDelCache complete:(custom_complete_B)complete { //逻辑待优化 BOOL isSuc = false; BOOL isDelUploadingModel = false; NSMutableArray *curDelArr = [NSMutableArray arrayWithArray:delArr]; for (uploadFileDataModel *uploadFileDataMod in curDelArr) { NSMutableString* where = [[NSMutableString alloc] initWithString:@"where "]; NSString *curStr = [NSString stringWithFormat:@"%@=%@ ",bg_sqlKey(@"bg_id"),bg_sqlValue(uploadFileDataMod.bg_id)]; [where appendString:curStr]; isSuc = [uploadFileDataModel bg_delete:upLoadFile_image_tableName where:where]; [self handleDatabaseArrByDelete:uploadFileDataMod]; //删除本地图片 if(isSuc && isDelCache){ //判断是否可以删除本地缓存 if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadingArr = _databaseArr[0]; NSMutableArray *uploadDoneArr = _databaseArr[1]; NSMutableArray *uploadFailArr = _databaseArr[2]; BOOL isNeedDel = YES; for (uploadFileDataModel *baseUploadFileDataMod in uploadingArr) { if([_curUploadFileDataModel.filename isEqualToString:baseUploadFileDataMod.filename] ){ isNeedDel = NO; break; } } if(!isNeedDel){ for (uploadFileDataModel *baseUploadFileDataMod in uploadDoneArr) { if([_curUploadFileDataModel.filename isEqualToString:baseUploadFileDataMod.filename] ){ isNeedDel = NO; break; } } } if(!isNeedDel){ for (uploadFileDataModel *baseUploadFileDataMod in uploadFailArr) { if([_curUploadFileDataModel.filename isEqualToString:baseUploadFileDataMod.filename] ){ isNeedDel = NO; break; } } } if(isNeedDel){ if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.videoFirstImageName type:uploadFileTypeImage error:nil]; [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } else{ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeImage error:nil]; } } } } if(isSuc && !isDelCache){//上传报云机已经存在文件了 查询本地是否有任务记录 [self handleRetryUploadAndDelRecordFun:uploadFileDataMod]; } //是否在删除上传中的任务 if(_fileModelDataArr && _fileModelDataArr.count >0) { for (uploadFileDataModel *curUploadFileDataMod in _fileModelDataArr) { if(curUploadFileDataMod.bg_id.integerValue == uploadFileDataMod.bg_id.integerValue){ [_fileModelDataArr removeObject:curUploadFileDataMod]; break; } } } if(!isDelUploadingModel){ if(_curUploadFileDataModel.bg_id.integerValue == uploadFileDataMod.bg_id.integerValue){ isDelUploadingModel = YES; [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileSuspendNotification object:nil]; } } } if(isDelUploadingModel){ _isUploadIngType = NO; if(_fileModelDataArr.count >=1){ [self beginUploadFileFun]; } } //继续下一个 // if(_fileModelDataArr){ // [_fileModelDataArr removeObject:_curUploadFileDataModel]; // _isUploadIngType = NO; // if(_fileModelDataArr.count >=1){ // [self beginUploadFileFun]; // } // } complete(isSuc); } #pragma mark 处理重复上传文件的问题 - (void)handleRetryUploadAndDelRecordFun:(uploadFileDataModel *)uploadFileDataMod { NSLock *lock = [NSLock new]; [lock lock]; if(!_databaseArr && _databaseArr.count != 3){ return; } NSMutableArray * doneArr = _databaseArr[1]; NSMutableArray * failArr = _databaseArr[2]; BOOL isNeedDelType = YES; for (uploadFileDataModel *doneModel in doneArr) { if([doneModel.localIdentifier isEqualToString:uploadFileDataMod.localIdentifier]){ isNeedDelType = NO; break; } } if(isNeedDelType){ for (uploadFileDataModel *failModel in failArr) { if([failModel.localIdentifier isEqualToString:uploadFileDataMod.localIdentifier]){ isNeedDelType = NO; break; } } } if(isNeedDelType){ if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.videoFirstImageName type:uploadFileTypeImage error:nil]; [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } else{ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeImage error:nil]; } } else{//视频文件是要删除的 if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } } [lock unlock]; } @end