Pro*_*ver 8 iphone objective-c ios afnetworking phasset
目前我正在使用以下代码上传视频:
NSURLRequest *urlRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[[entity uploadUrl]absoluteString] parameters:entity.params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[UploadModel getAssetData:entity.asset resultHandler:^(NSData *filedata) {
NSString *mimeType =[FileHelper mimeTypeForFileAtUrl:entity.fileUrl];
// NSError *fileappenderror;
[formData appendPartWithFileData:filedata name:@"data" fileName: entity.filename mimeType:mimeType];
}];
} error:&urlRequestError];
Run Code Online (Sandbox Code Playgroud)
GetAssetData方法
+(void)getAssetData: (PHAsset*)mPhasset resultHandler:(void(^)(NSData *imageData))dataResponse{
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
[[PHImageManager defaultManager] requestAVAssetForVideo:mPhasset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
if ([asset isKindOfClass:[AVURLAsset class]]) {
NSURL *localVideoUrl = [(AVURLAsset *)asset URL];
NSData *videoData= [NSData dataWithContentsOfURL:localVideoUrl];
dataResponse(videoData);
}
}];
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题是,无论何时上传大/多个视频文件,应用程序都会耗尽内存.我想这是因为请求NSDATA(aka filedata)上传文件(参见上面的方法).我试图使用
它在模拟器上工作的方法appendPartWithFileURLintead 请求文件路径
appendPartWithFileData.并且在具有错误的实际设备上失败,该错误无法通过指定的路径读取文件.我在这里用PHAsset + AFNetworking描述了这个问题
.无法将文件上传到真实设备上的服务器
=======================================
更新:我已修改我的代码,以测试通过新iPhone 6s +上的本地路径上传文件的方法,如下所示
NSURLRequest *urlRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[[entity uploadUrl]absoluteString] parameters:entity.params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSString *mimeType =[FileHelper mimeTypeForFileAtUrl:entity.fileUrl];
NSError *fileappenderror;
[formData appendPartWithFileURL:entity.fileUrl name:@"data" fileName:entity.filename mimeType:mimeType error:&fileappenderror];
if (fileappenderror) {
[Sys MyLog: [NSString stringWithFormat:@"Failed to append: %@", [fileappenderror localizedDescription] ] ];
}
} error:&urlRequestError];
Run Code Online (Sandbox Code Playgroud)
在iPhone 6s +上进行测试可以提供更清晰的日志警告它是调用方法的结果 appendPartWithFileURL
<Warning>: my_log: Failed to append file: The operation couldn’t be completed. File URL not reachable.
deny(1) file-read-metadata /private/var/mobile/Media/DCIM/100APPLE/IMG_0008.MOV
15:41:25 iPhone-6s kernel[0] <Notice>: Sandbox: My_App(396) deny(1) file-read-metadata /private/var/mobile/Media/DCIM/100APPLE/IMG_0008.MOV
15:41:25 iPhone-6s My_App[396] <Warning>: my_log: Failed to append file: The file “IMG_0008.MOV” couldn’t be opened because you don’t have permission to view it.
Run Code Online (Sandbox Code Playgroud)
这是用于从PHAsset获取本地文件路径的代码
if (mPhasset.mediaType == PHAssetMediaTypeImage) {
PHContentEditingInputRequestOptions * options = [[PHContentEditingInputRequestOptions alloc]init];
options.canHandleAdjustmentData = ^BOOL(PHAdjustmentData *adjustmeta){
return YES;
};
[mPhasset requestContentEditingInputWithOptions:options completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info) {
dataResponse(contentEditingInput.fullSizeImageURL);
}];
}else if(mPhasset.mediaType == PHAssetMediaTypeVideo){
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
[[PHImageManager defaultManager] requestAVAssetForVideo:mPhasset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
if ([asset isKindOfClass:[AVURLAsset class]]) {
NSURL *localVideoUrl = [(AVURLAsset *)asset URL];
dataResponse(localVideoUrl);
}
}];
}
Run Code Online (Sandbox Code Playgroud)
所以问题仍然是相同的 - 上传到服务器的文件是空的
Pro*_*ver 12
上面提出的解决方案只是部分正确(并且我之前发现它).由于系统不允许读取沙箱之外的文件,因此文件路径无法访问(读/写)文件,只是复制了文件.在iOS 9及更高版本中,Photos Framework提供了API(它不能通过NSFileManager完成,但只能使用Photos framework api)将文件复制到App的沙箱目录中.这是我在挖掘文档和头文件后使用的代码.
首先将文件复制到app sandbox目录.
// Assuming PHAsset has only one resource file.
PHAssetResource * resource = [[PHAssetResource assetResourcesForAsset:myPhasset] firstObject];
+(void)writeResourceToTmp: (PHAssetResource*)resource pathCallback: (void(^)(NSURL*localUrl))pathCallback {
// Get Asset Resource. Take first resource object. since it's only the one image.
NSString *filename = resource.originalFilename;
NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:filename];
NSURL *localpath = [NSURL fileURLWithPath:pathToWrite];
PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
options.networkAccessAllowed = YES;
[[PHAssetResourceManager defaultManager] writeDataForAssetResource:resource toFile:localpath options:options completionHandler:^(NSError * _Nullable error) {
if (error) {
[Sys MyLog: [NSString stringWithFormat:@"Failed to write a resource: %@",[error localizedDescription]]];
}
pathCallback(localpath);
}];
} // Write Resource into Tmp
Run Code Online (Sandbox Code Playgroud)
上传任务本身
NSURLRequest *urlRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST"
URLString:[[entity uploadUrl]absoluteString] parameters:entity.params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// Assuming PHAsset has only one resource file.
PHAssetResource * resource = [[PHAssetResource assetResourcesForAsset:myPhasset] firstObject];
[FileHelper writeResourceToTmp:resource pathCallback:^(NSURL *localUrl)
{
[formData appendPartWithFileURL: localUrl name:@"data" fileName:entity.filename mimeType:mimeType error:&fileappenderror];
}]; // writeResourceToTmp
}// End Url Request
AFHTTPRequestOperation * operation = [[AFHTTPRequestOperation alloc ] initWithRequest:urlRequest];
//.....
// Further steps are described in the AFNetworking Docs
Run Code Online (Sandbox Code Playgroud)
这种上传方法有一个明显的缺点..如果设备进入"睡眠模式",你会被搞砸..因此这里推荐的上传方法是使用方法.uploadTaskWithRequest:fromFile:progress:completionHandler在AFURLSessionManager.
对于iOS 9以下的版本..在图像的情况下你可以NSDATA从PHAsset我的问题的代码中获取来自..并上传它.或者在上传之前先将它写入您的应用沙箱存储.对于大文件,此方法不可用.或者,您可能希望使用图像/视频选择器导出文件ALAsset.ALAsset提供api,允许您从存储中读取文件.但是您必须在上传之前将其写入沙箱存储.
为每个视频创建NSData可能不好,因为视频(或任何其他文件)可能比设备的RAM大得多,我建议上传为"文件"而不是"数据",如果你附加文件,它将从磁盘块逐块发送数据,并且不会尝试立即读取整个文件,请尝试使用
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
name:(NSString *)name
error:(NSError * __autoreleasing *)error
Run Code Online (Sandbox Code Playgroud)
另请参阅https://github.com/AFNetworking/AFNetworking/issues/828
在你的情况下,像这样使用它
NSURLRequest *urlRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[[entity uploadUrl]absoluteString] parameters:entity.params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:entity.fileUrl name:entity.filename error:&fileappenderror];
if(fileappenderror) {
NSLog(@"%@",fileappenderror);
}
} error:&urlRequestError];
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5117 次 |
| 最近记录: |