// // backupsFileManager.m // 隐私保护 // // Created by xd h on 2024/1/3. // #import "backupsFileManager.h" #import "cachesFileManager.h" #import "connectDeviceManager.h" #import "AFNetworkReachabilityManager.h" @interface backupsFileManager () /**检测任务10s后 无反馈重新开始 */ @property (nonatomic, assign) NSInteger taskRenewTime; // @property (nonatomic,strong)photosBackupsTaskModel *lastModel;//最后一次备份的数据 @end @implementation backupsFileManager static backupsFileManager * cur_backupsFileShareInstance = nil; +(backupsFileManager *)shareInstance; { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ cur_backupsFileShareInstance = [[backupsFileManager alloc] init]; }); return cur_backupsFileShareInstance; } - (id)init { self = [super init]; if (self) { //[self initManager]; } return self; } - (void)AutohandlePhotosBackupsFun { NSString *curSdnId = ksharedAppDelegate.DeviceThirdIdMod.data.sdnId; if(!_sdnId || ![curSdnId isEqualToString:_sdnId]) {//没有备份过 或者更换设备了 [self handlePhotosBackupsFun]; } else{ [self checkReBackupsFileFun]; } } - (void)handlePhotosBackupsFun { BOOL haveOpenBackups = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_photo_backups_state)]; if(!haveOpenBackups){ return; } if(ksharedAppDelegate.DisabledFileTransferType){ return; } //相册权限 if (![[TZImageManager manager] authorizationStatusAuthorized]){ [HWDataManager setBoolWithKey:Const_photo_backups_state value:NO]; return; } NSString *curSdnId = ksharedAppDelegate.DeviceThirdIdMod.data.sdnId; _sdnId = curSdnId; [photosBackupsTaskModel bg_findAsync:backups_photos_tableName limit:0 orderBy:nil desc:YES complete:^(NSArray * _Nullable array) { if(!array || array.count == 0){ [self getAllAlbumsFun]; return; } if(array.count >1){ [self keepDatabaseOneDataFun]; } self->_lastModel = array.firstObject; HLog(@"1 bg_id:%@",self->_lastModel.bg_id); if(self->_lastModel.isBackupsSuspendType == backupsSuspendByUser){ return; } if(self->_lastModel.curBackupsState == backupsStateFail ||self->_lastModel.curBackupsState == backupsStateDone){//上次备份完成 [self getAllAlbumsFun]; } else{//继续上次的备份任务 [self handelBackupsModelFun:self->_lastModel]; } }]; } - (void)keepDatabaseOneDataFun { [photosBackupsTaskModel bg_deleteFirstObject:backups_photos_tableName]; //[photosBackupsTaskModel bg_findAsync:backups_photos_tableName } //备份开始查询相册 - (void)getAllAlbumsFun { // KWeakSelf [[TZImageManager manager] getAllAlbums:YES allowPickingImage:YES needFetchAssets:NO completion:^(NSArray *models) { if(models.count >= 1){ TZAlbumModel *curAlbumModel= models.firstObject; photosBackupsTaskModel * taskModel = [photosBackupsTaskModel new]; //taskModel.count = curAlbumModel.count; //taskModel.result = curAlbumModel.result; taskModel.failCount = 0; taskModel.didBackupsCount = 0; taskModel.bg_tableName = backups_photos_tableName; //备份路径 NSString * backupsDefaultPath = [HWDataManager getStringWithKey:stringKeyAddSn(Const_photo_backups_default_path)]; if(!backupsDefaultPath || backupsDefaultPath.length == 0){ backupsDefaultPath = Const_default_backups_path; [HWDataManager setStringWithKey:stringKeyAddSn(Const_photo_backups_default_path) value:backupsDefaultPath]; } NSString *lastStr= [backupsDefaultPath substringFromIndex:backupsDefaultPath.length-1]; if(![lastStr isEqualToString:@"/"]){ backupsDefaultPath = [[NSString alloc] initWithFormat:@"%@/",backupsDefaultPath]; } taskModel.backupsPath = backupsDefaultPath; NSMutableString *allLocalIdentifier= [NSMutableString new]; for (PHAsset *asset in curAlbumModel.result) { if (asset.localIdentifier) { if(allLocalIdentifier.length >0){ [allLocalIdentifier appendString:@"&"]; } [allLocalIdentifier appendString:asset.localIdentifier]; } } taskModel.totalLocalIdentifier = allLocalIdentifier; if(self->_lastModel && self->_lastModel.totalLocalIdentifier && (self->_lastModel.backupsPath && [self->_lastModel.backupsPath isEqualToString:taskModel.backupsPath])){//相册备份排重 taskModel.curTaskLocalIdentifier = [weakSelf AlbumBackupsHandleNew:taskModel]; taskModel.PreDidBackupsCount = self->_lastModel.PreDidBackupsCount + self->_lastModel.didBackupsCount; } else{ taskModel.curTaskLocalIdentifier = allLocalIdentifier; } taskModel.count = [taskModel.curTaskLocalIdentifier componentsSeparatedByString:@"&"].count; HLog(@"2 bg_id:%@",taskModel.bg_id); [taskModel bg_saveAsync:^(BOOL isSuccess) { if(!isSuccess){ HLog(@"\n\nError!!!\n\n"); } else{ //[self handelBackupsModelFun:taskModel]; [self handlePhotosBackupsFun]; } }]; } }]; } - (NSString*)AlbumBackupsHandleNew:(photosBackupsTaskModel * )taskModel { NSArray* curLocalIdentifierArr = [taskModel.totalLocalIdentifier componentsSeparatedByString:@"&"]; NSArray* preLocalIdentifierArr = [_lastModel.totalLocalIdentifier componentsSeparatedByString:@"&"]; NSMutableArray *allArr = [NSMutableArray arrayWithArray:curLocalIdentifierArr]; for (NSString*localIdentifier in preLocalIdentifierArr) { for (NSString* newlocalIdentifier in allArr) { if([localIdentifier isEqualToString:newlocalIdentifier]){ [allArr removeObject:newlocalIdentifier]; break; } } } NSMutableString *allLocalIdentifier= [NSMutableString new]; for (NSString* newlocalIdentifier in allArr) { if(allLocalIdentifier.length >0){ [allLocalIdentifier appendString:@"&"]; } [allLocalIdentifier appendString:newlocalIdentifier]; } return allLocalIdentifier; } - (void)handelBackupsModelFun:(photosBackupsTaskModel*)backupsTaskModel { _curPhotosBackupsTaskMod = backupsTaskModel; _curPhotosBackupsTaskMod.isBackupsSuspendType = backupsSuspendNone; _curPhotosBackupsTaskMod.curBackupsState = backupsStateUploading; _curPhotosBackupsTaskMod.LocalIdentifierArr = [backupsTaskModel.curTaskLocalIdentifier componentsSeparatedByString:@"&"]; if(_curPhotosBackupsTaskMod.LocalIdentifierArr.count == 0){ _curPhotosBackupsTaskMod.didBackupsCount = 0; _curPhotosBackupsTaskMod.curBackupsState = backupsStateDone; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; return; } if(_curPhotosBackupsTaskMod.LocalIdentifierArr.count <= (_curPhotosBackupsTaskMod.didBackupsCount + _curPhotosBackupsTaskMod.failCount)) { _curPhotosBackupsTaskMod.curBackupsState = backupsStateDone; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; return; } [self beginBackupsFileFun]; } - (void)beginBackupsFileFun { BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)]; if(!isCanUseCellular){//不允许流量上传 // if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){ return; } } self.taskRenewTime = [iTools getNowTimeStamp]; NSInteger index = _curPhotosBackupsTaskMod.didBackupsCount + _curPhotosBackupsTaskMod.failCount; if(!_curPhotosBackupsTaskMod.LocalIdentifierArr){ _curPhotosBackupsTaskMod.LocalIdentifierArr = [_curPhotosBackupsTaskMod.curTaskLocalIdentifier componentsSeparatedByString:@"&"]; } if(index >= _curPhotosBackupsTaskMod.LocalIdentifierArr.count){ _curPhotosBackupsTaskMod.curBackupsState = backupsStateDone; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; _curPhotosBackupsTaskMod = nil; return; } NSString *curLocalIdentifier = _curPhotosBackupsTaskMod.LocalIdentifierArr[index]; if(!curLocalIdentifier || curLocalIdentifier.length == 0) { [self getDataWrongToChangeFailFun]; return; } _curPhotosBackupsTaskMod.didUploadBytes = 0; _curPhotosBackupsTaskMod.preDidUploadBytes = 0; _curPhotosBackupsTaskMod.totalBytes = 0; PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil]; PHAsset *curAsset = fetchResult.firstObject; NSString *fileName = [curAsset valueForKey:@"filename"];; if(!fileName){ [self getDataWrongToChangeFailFun]; return; } _curPhotosBackupsTaskMod.filename = fileName; KWeakSelf if(curAsset.mediaType == PHAssetMediaTypeImage){ _curPhotosBackupsTaskMod.curUploadFileType = uploadFileTypeImage; PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; options.networkAccessAllowed = YES; // Allow downloading from iCloud options.version = PHImageRequestOptionsVersionCurrent; options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; [[PHImageManager defaultManager] requestImageDataForAsset:curAsset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { // 直接得到最终的 NSData 数据 if (imageData) { [weakSelf afterGetImageDataFun:imageData]; } else{ [weakSelf getDataWrongToChangeFailFun]; } }]; } else{ _curPhotosBackupsTaskMod.curUploadFileType = uploadFileTypeVideo; //判断文件是否在app内 BOOL didSaveFile = [cachesFileManager checkFileIsSaveState:_curPhotosBackupsTaskMod.filename withType:uploadFileTypeVideo]; if(didSaveFile){ [self afterGetVideoDataFun]; return; } //真正的视频数据 PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; options.version = PHVideoRequestOptionsVersionOriginal; options.networkAccessAllowed = YES; // Allow downloading from iCloud [[PHImageManager defaultManager] requestAVAssetForVideo:curAsset 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:self->_curPhotosBackupsTaskMod.filename error:nil]; if (isSuc) { [weakSelf afterGetVideoDataFun]; } else{ [weakSelf getDataWrongToChangeFailFun]; } } else{ [weakSelf getDataWrongToChangeFailFun]; } }]; } } - (void)getDataWrongToChangeFailFun { [self deleteVideoFun]; _curPhotosBackupsTaskMod.failCount += 1; [self RefreshDatabaseFun]; if(_curPhotosBackupsTaskMod.curBackupsState == backupsStateSuspend){ return; } [self beginBackupsFileFun]; } - (void)changeBackupsFileStateToFailWith:(NSString*)errorStr { [self deleteVideoFun]; _curPhotosBackupsTaskMod.curBackupsState = backupsStateFail; _curPhotosBackupsTaskMod.backupsTipMsg = errorStr; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; } - (void)RefreshDatabaseFun { HLog(@"3 bg_id:%@",_curPhotosBackupsTaskMod.bg_id); [_curPhotosBackupsTaskMod bg_saveOrUpdateAsync:^(BOOL isSuccess) { if(isSuccess){ } }]; } - (void)afterGetImageDataFun:(NSData*)imageData { _curPhotosBackupsTaskMod.imageData = imageData; _curPhotosBackupsTaskMod.didUploadBytes = 0; _curPhotosBackupsTaskMod.totalBytes = [imageData length]; [[webSocketManager shareInstance] beginGotoBackupsFileFunBy:_curPhotosBackupsTaskMod]; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; } - (void)deleteVideoFun { if(_curPhotosBackupsTaskMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:_curPhotosBackupsTaskMod.filename type:uploadFileTypeVideo error:nil]; } } - (void)afterGetVideoDataFun { NSString *filePath = [cachesFileManager getFilePathWithName:_curPhotosBackupsTaskMod.filename type:uploadFileTypeVideo]; // 文件路径 NSFileManager *manager0 = [NSFileManager defaultManager]; if([manager0 fileExistsAtPath:filePath]) { NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; // 创建文件句柄 if (fileHandle) { long long endOfFile = [fileHandle seekToEndOfFile]; _curPhotosBackupsTaskMod.didUploadBytes = 0; _curPhotosBackupsTaskMod.totalBytes = endOfFile; [fileHandle closeFile]; } } [[webSocketManager shareInstance] beginGotoBackupsFileFunBy:_curPhotosBackupsTaskMod]; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; } - (void)backupsFileDoneFun { [self deleteVideoFun]; _curPhotosBackupsTaskMod.didBackupsCount += 1; // if(!_curPhotosBackupsTaskMod.didBackupsOneFileType) // { // _curPhotosBackupsTaskMod.curTaskBackupsCount += 1; // } [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; if(_curPhotosBackupsTaskMod.curBackupsState == backupsStateSuspend){ return; } //延时 进度条视觉效果 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self beginBackupsFileFun]; }); } //修改文件上传的状态 - (void)changeBackupsFileStateFun { self.taskRenewTime = [iTools getNowTimeStamp]; if(!_curPhotosBackupsTaskMod){ return; } [[NSNotificationCenter defaultCenter] postNotificationName:backupsFileRefreshNotification object:_curPhotosBackupsTaskMod]; } - (void)suspendBackupsFileFun { if(!_curPhotosBackupsTaskMod){ return; } _curPhotosBackupsTaskMod.curBackupsState = backupsStateSuspend; _curPhotosBackupsTaskMod.backupsTipMsg = NSLocalizedString(@"File_backups_Record_tip_Suspend",nil); [_curPhotosBackupsTaskMod bg_saveOrUpdateAsync:^(BOOL isSuccess) { if(isSuccess){ [self changeBackupsFileStateFun]; } }]; } //文件重新备份 - (void)reBackupsFileFunBy:(photosBackupsTaskModel*)model { model.isBackupsSuspendType = backupsSuspendNone; model.curBackupsState = backupsStateUploading; _curPhotosBackupsTaskMod = model; [self RefreshDatabaseFun]; [self changeBackupsFileStateFun]; [self beginBackupsFileFun]; // [_curPhotosBackupsTaskMod bg_saveOrUpdateAsync:^(BOOL isSuccess) { // if(isSuccess){ // [self beginBackupsFileFun]; // } // }]; } //文件重新备份 - (void)reBackupsFileFun { [self handlePhotosBackupsFun]; //if(_curPhotosBackupsTaskMod.curBackupsState != backupsStateUploading) if(self->_lastModel.curBackupsState != backupsStateUploading){ if(self->_lastModel.curBackupsState == backupsStateFail ||self->_lastModel.curBackupsState == backupsStateDone){//上次备份完成 [self getAllAlbumsFun]; } else{//继续上次的备份任务 [self handelBackupsModelFun:self->_lastModel]; } } } //检查是否需要重新备份 - (void)checkReBackupsFileFun { if(!_curPhotosBackupsTaskMod){ return; } if(_curPhotosBackupsTaskMod.curBackupsState != backupsStateUploading){ return; } NSInteger curTime = [iTools getNowTimeStamp]; if(self.taskRenewTime == 0){ return; } if(curTime - self.taskRenewTime < 10){ return; } [self beginBackupsFileFun]; } //检查是否在备份中 - (BOOL)checkBackupsingFun{ if(!_curPhotosBackupsTaskMod){ return NO; } if(_curPhotosBackupsTaskMod.curBackupsState == backupsStateSuspend){ return NO; } return YES; } @end