PHAsset + AFNetworking。无法在真实设备上将文件上传到服务器
PHAsset + AFNetworking. Unable to upload files to the server on a real device
目前我正在使用以下代码上传文件到服务器
NSURLRequest *urlRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[[entity uploadUrl]absoluteString] parameters:entity.params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// Get file url
[UploadModel getAassetUrl:entity.asset resultHandler:^(NSURL *fileUrl) {
NSError *fileappenderror;
// Append
[formData appendPartWithFileURL:fileUrl name:@"data" error:&fileappenderror];
if (fileappenderror) {
[Sys MyLog: [fileappenderror localizedDescription] ];
}
}];
} error:&urlRequestError];
/*getAassetUrl */
+(void)getAassetUrl: (PHAsset*)mPhasset resultHandler:(void(^)(NSURL *imageUrl))dataResponse{
PHImageRequestOptions * requestOption = [[PHImageRequestOptions alloc] init];
requestOption.synchronous = YES;
requestOption.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
[[PHImageManager defaultManager] requestImageDataForAsset:mPhasset options:requestOption resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
dataResponse([info objectForKey:@"PHImageFileURLKey"]);
}];
}
这种方法在模拟器上有效,但在真实设备上失败:空文件上传到服务器很可能是由于无法从本地存储读取。
日志显示通知
Notice: Sandbox: MyApp(213) deny file-read-data
/private/var/mobile/Media/DCIM/101APPLE/IMG_1570.PNG
我相信这个注释意味着应用程序无法通过指定路径访问文件。
此外,我还尝试了另一种上传文件的方法,即附加从请求 PHAsset 数据返回的 NSData。但这种方法在大型媒体文件的情况下不可用。因为整个文件都被加载到内存中。
有什么想法吗?
requestImageDataForAsset
返回的 NSData 对象是内存映射的 - 因此整个文件不会加载到内存中。所以这个方法对图像没有任何问题。
对于视频,您应该使用适当的方法 requestExportSessionForVideo
或 requestAVAssetForVideo
如果你可以限制你的部署目标到iOS9,你也应该看看PHAssetResourceManager
的方法
您不应该对大文件使用 requestImageDataForAsset(_:options:resultHandler:)
。原因是您不想将整个媒体文件加载到内存中,您将很快 运行 内存不足并且应用程序将崩溃。这通常意味着您不应该将它用于大图像或几乎任何视频。
根据我的经验,尝试直接从 PHAsset 资源 url 上传会失败。 Apple 似乎没有授予我们直接从 PHAsset 源文件上传所需的权限。请参阅论坛 post here。这很痛苦,因为如果我们想上传视频,它会迫使我们使用大量额外的磁盘 space。
要获取您打算上传的视频文件的本地文件 url,您需要使用以下任一方法:
requestExportSessionForVideo(_:options:exportPreset:resultHandler:)
或
requestAVAssetForVideo(_:options:resultHandler:)
您将使用这些方法将视频文件的副本导出到您控制的磁盘位置。并从该文件上传。额外功能:如有必要,这两种方法都会从 iCloud 下载文件。
查看 VimeoUpload 库以了解与视频上传相关的所有内容的详细信息。免责声明:我是图书馆的作者之一。
即使您没有上传到 Vimeo 服务器,您也可以使用 VimeoUpload 中包含的 PHAssetExportSessionOperation
和 ExportOperation
类 来完成您想要的寻找做。有关 为 PHAsset 获取文件 url 的详细信息,请参阅 repo README。它还包括用于 为 ALAsset 获取文件 url 的工具。
如果您对使用 PHAssetExportSessionOperation
或 ExportOperation
不感兴趣,请查看它们的实现以了解有关如何在后台使用 Apple 类 的详细信息。
目前我正在使用以下代码上传文件到服务器
NSURLRequest *urlRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[[entity uploadUrl]absoluteString] parameters:entity.params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// Get file url
[UploadModel getAassetUrl:entity.asset resultHandler:^(NSURL *fileUrl) {
NSError *fileappenderror;
// Append
[formData appendPartWithFileURL:fileUrl name:@"data" error:&fileappenderror];
if (fileappenderror) {
[Sys MyLog: [fileappenderror localizedDescription] ];
}
}];
} error:&urlRequestError];
/*getAassetUrl */
+(void)getAassetUrl: (PHAsset*)mPhasset resultHandler:(void(^)(NSURL *imageUrl))dataResponse{
PHImageRequestOptions * requestOption = [[PHImageRequestOptions alloc] init];
requestOption.synchronous = YES;
requestOption.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
[[PHImageManager defaultManager] requestImageDataForAsset:mPhasset options:requestOption resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
dataResponse([info objectForKey:@"PHImageFileURLKey"]);
}];
}
这种方法在模拟器上有效,但在真实设备上失败:空文件上传到服务器很可能是由于无法从本地存储读取。 日志显示通知
Notice: Sandbox: MyApp(213) deny file-read-data /private/var/mobile/Media/DCIM/101APPLE/IMG_1570.PNG
我相信这个注释意味着应用程序无法通过指定路径访问文件。 此外,我还尝试了另一种上传文件的方法,即附加从请求 PHAsset 数据返回的 NSData。但这种方法在大型媒体文件的情况下不可用。因为整个文件都被加载到内存中。
有什么想法吗?
requestImageDataForAsset
返回的 NSData 对象是内存映射的 - 因此整个文件不会加载到内存中。所以这个方法对图像没有任何问题。
对于视频,您应该使用适当的方法 requestExportSessionForVideo
或 requestAVAssetForVideo
如果你可以限制你的部署目标到iOS9,你也应该看看PHAssetResourceManager
您不应该对大文件使用 requestImageDataForAsset(_:options:resultHandler:)
。原因是您不想将整个媒体文件加载到内存中,您将很快 运行 内存不足并且应用程序将崩溃。这通常意味着您不应该将它用于大图像或几乎任何视频。
根据我的经验,尝试直接从 PHAsset 资源 url 上传会失败。 Apple 似乎没有授予我们直接从 PHAsset 源文件上传所需的权限。请参阅论坛 post here。这很痛苦,因为如果我们想上传视频,它会迫使我们使用大量额外的磁盘 space。
要获取您打算上传的视频文件的本地文件 url,您需要使用以下任一方法:
requestExportSessionForVideo(_:options:exportPreset:resultHandler:)
或
requestAVAssetForVideo(_:options:resultHandler:)
您将使用这些方法将视频文件的副本导出到您控制的磁盘位置。并从该文件上传。额外功能:如有必要,这两种方法都会从 iCloud 下载文件。
查看 VimeoUpload 库以了解与视频上传相关的所有内容的详细信息。免责声明:我是图书馆的作者之一。
即使您没有上传到 Vimeo 服务器,您也可以使用 VimeoUpload 中包含的 PHAssetExportSessionOperation
和 ExportOperation
类 来完成您想要的寻找做。有关 为 PHAsset 获取文件 url 的详细信息,请参阅 repo README。它还包括用于 为 ALAsset 获取文件 url 的工具。
如果您对使用 PHAssetExportSessionOperation
或 ExportOperation
不感兴趣,请查看它们的实现以了解有关如何在后台使用 Apple 类 的详细信息。