// // 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; } _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:YES 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]; } } [self->_databaseArr addObject:otherArr]; [self->_databaseArr addObject:doneArr]; [self->_databaseArr addObject:failArr]; 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; for (TZAssetModel * model in indexPathsForSelectedItems) { uploadFileDataModel * curModel = [uploadFileDataModel new]; curModel.asset = model.asset; curModel.localIdentifier = model.asset.localIdentifier; 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];; } }]; //真正的视频数据 // PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; // options.version = PHVideoRequestOptionsVersionOriginal; // [[PHImageManager defaultManager] requestAVAssetForVideo:curModel.asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) { // if ([asset isKindOfClass:[AVURLAsset class]]) { // // AVURLAsset* urlAsset = (AVURLAsset*)asset; // NSData *videoData = [NSData dataWithContentsOfURL:urlAsset.URL]; // // if (videoData) { // curModel.videoData = videoData; // [cachesFileManager getFileNameWithContent:curModel.videoData fileName:curModel.filename type:uploadFileTypeVideo]; // curModel.videoData = nil; // } // } // }]; } 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++) 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); [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]; } } else if(curUploadStateType == uploadStateFail){ } [curModel bg_saveOrUpdateAsync:^(BOOL isSuccess) { HLog(@"%@ 写入 %@", model.filename, isSuccess ? @"成功":@"失败"); }]; } complete(YES); }]; } //暂停上传完成 - (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; for (uploadFileDataModel *uploadFileDataMod in delArr) { 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]; //删除本地图片 if(isSuc && isDelCache){ 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]; } } complete(isSuc); //继续下一个 if(_fileModelDataArr){ [_fileModelDataArr removeObject:_curUploadFileDataModel]; _isUploadIngType = NO; if(_fileModelDataArr.count >=1){ [self beginUploadFileFun]; } } } #pragma mark 处理重复上传文件的问题 - (void)handleRetryUploadAndDelRecordFun:(uploadFileDataModel *)uploadFileDataMod { 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]; } } } @end