#|iOS13上传相册视频Code=1 "Operation not permitted"


文章目录

  • iOS13上传相册视频Code=1 "Operation not permitted"
    • 上传报错
    • 分析问题
    • 解决问题
    • 发现问题
    • 解决问题

iOS13上传相册视频Code=1 “Operation not permitted”
在做文件上传时候,发现iOS13上,选择相册的视频上传,会报无权限访问文件的错误,iOS13以下的系统不会出这个问题,可能部分机型上会有吧,但是我没发现。
上传报错 报错信息:
Error Domain=NSCocoaErrorDomain Code=257 "The file "trim.166DC0B6-0C86-4EC3-BCBD-F29684A5566C/tmp/1C91514D-C987-4C1C-BEBF-6A7F071F1435.MOV" couldn't be opened because you don't has permission to view it."
#|iOS13上传相册视频Code=1 "Operation not permitted"
文章图片

分析问题 看了下iOS12和iOS13上获取到的文件路径:
iOS12
file:///private/var/mobile/Containers/Data/Application/166DC0B6-0C86-4EC3-BCBD-F29684A5566C/tmp/1C91514D-C987-4C1C-BEBF-6A7F071F1435.MOV";
iOS13
file:///private/var/mobile/Containers/Data/Application/PluginKitPgin/166DC0B6-0C86-4EC3-BCBD-F29684A5566C/tmp/1C91514D-C987-4C1C-BEBF-6A7F071F1435.MOV";
发现iOS12的路径多了一个PluginKitPgin文件夹,这导致文件访问受限。
但是有意思的是通过iOS13的这个路径可以拿到问价你的二进制数据
+ (NSData *)fileData:(NSString *)filePath { NSFileHandle *fileHande = [NSFileHandle fileHandleForReadingAtPath:filePath]; return [fileHande readDataToEndOfFile]; }

解决问题 这样的话先拿到文件,然后写入沙盒,然后通过沙盒路径去上传就ok了,大致代码是这样的:
//视频文件 if ([mediaType isEqualToString:@"public.movie"]) { NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL]; NSString *videoPath = url.path; // <13.0可以直接上传 if ([[UIDevice currentDevice].systemVersion floatValue] < 13.0) { //上传 [self addUploadFileWithPath:videoPath]; } //13.0 先将文件存在在沙盒,然后上传 else { NSString *datapath = [self writeFileToDocPaths:videoPath]; [self addUploadFileWithPath:datapath]; } }

将数据写入沙盒中
-(NSString *)writeFileToDocPaths:(NSString *)filePath { //读取相册中的文件 NSData *data = [VHUploaderModel fileData:filePath]; //将文件写入沙盒 NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *dataPath = [self getFilePath:[NSString stringWithFormat:@"%@",[filePath lastPathComponent]]]; if (![fileManager fileExistsAtPath:dataPath]) {//文件是否存在 [fileManager createFileAtPath:dataPath contents:nil attributes:nil]; } NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:dataPath]; [fileHandle seekToEndOfFile]; [fileHandle writeData:data]; [fileHandle closeFile]; return dataPath; } - (NSString *)getFilePath:(NSString *)fileName { NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES).firstObject; return [docPath stringByAppendingPathComponent:fileName]; }

发现问题 发现读取大文件的时候,尤其是视频文件时,App的内存暴涨?为什么会这样呢?
后来我想明白了,暴涨就对了,内存不涨那次有问题呢。文件在磁盘上存储着,当我们读取它的时候,会将读到的数据放到缓存里,手机的缓存是有限,但是文件很大,所以内存会暴涨,而且直接卡爆,然后报limit xx m的错误。
【#|iOS13上传相册视频Code=1 "Operation not permitted"】把文件从磁盘读出来,然后再存储到别的地方,这种思想就很可怕,读出来整个文件那得占用多大的缓存啊。这个把文件都读出来,然后再写入的思想本来就是不对的。
正确的做法应该是,循环读取,每次读小一部分数据,然后写入文件,直到把整个文件读完保存完。
解决问题 正确的解决办法如下:
选择相册视频后,先写入沙盒中,然后再进行上传,不会报无权限的问题,内存也不会暴涨。
int32_t const VH_CHUNK_SIZE = 8 * 1024; //另存为 - (NSString *)writefile:(NSString *)filePath { //写入文件路径 NSString *toPath = [NSString stringWithFormat:@"%@/%@",NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject,[filePath lastPathComponent]]; //如果存在,先删除 if ([[NSFileManager defaultManager] fileExistsAtPath:toPath]) { [[NSFileManager defaultManager] removeItemAtPath:toPath error:nil]; } //创建文件路径 if (![[NSFileManager defaultManager] createFileAtPath:toPath contents:nil attributes:nil]) { return nil; } //打开文件 NSFileHandle *sourceHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:toPath]; if(sourceHandle == nil || writeHandle == nil) { return nil; } //读取文件写入 BOOL done = NO; while(!done) { @autoreleasepool{ NSData *data = [sourceHandle readDataOfLength:VH_CHUNK_SIZE]; if([data length] == 0) { done = YES; } [writeHandle seekToEndOfFile]; [writeHandle writeData:data]; data = nil; } } //关闭文件 [sourceHandle closeFile]; [writeHandle closeFile]; return toPath; }

上传完后别忘了清除本地文件
//删除本地上传的文件 - (BOOL)deletefile:(NSString *)uploadPath { if ([[NSFileManager defaultManager] fileExistsAtPath:uploadPath]) { return [[NSFileManager defaultManager] removeItemAtPath:uploadPath error:nil]; } return NO; }

    推荐阅读