【iOS】自定义相机(十)资源保存

 

相册

在前面的文章中,我们已经介绍了各种媒体获取的方式,还没介绍如何将这些媒体资源保存到相册中。本篇文章的保存方式是基于PHPhotoLibrary这个系统类的,下面将简单介绍保存使用的部分,其他功能详细请参见官方文档。

媒体类型

在自定义相机中,我们获取的媒体类型有以下三种,分别是静态照片、动态照片和视频。他们在捕获后的资源存在形式如下:

  • 静态照片:NSData
  • 动态照片:NSData + NSURL
  • 视频:NSURL

因此,我们向系统相册写入数据都是围绕着NSDataNSURL进行的。

权限问题

和获取相机、相册、麦克风数据一样,向系统相册写入数据也需要获取权限。在Info.plist中我们需要添加:


<key>NSPhotoLibraryAddUsageDescription</key>
<string>App需要您的同意,才能添加图片</string>

由于需要获取权限,我们在开发的时候就需要像打开相机一样小心,操作前务必检查权限,避免出现不好的用户体验。

PHPhotoLibrary 写入数据

我们需要先通过[PHPhotoLibrary sharedPhotoLibrary]获取PHPhotoLibrary的单例对象,再调用核心方法performChanges:completionHandler:。该方法用于向相册中异步写入资源数据,所以开发者只需要把写入数据的操作放在Changes中,完成回调放在completionHandler中即可。

Changes 操作

Changes操作由系统异步调用,PHPhotoLibrary规定我们在写入数据时候,需要使用PHAssetCreationRequest对象进行操作。主要分为以下两步走:

  1. 创建步骤:使用creationRequestForAsset类方法进行对象的创建
  2. 配置步骤:使用addResourceWithType:fileURL:options:addResourceWithType:data:options:配置需要保存的资源

不同类型媒体资源的保存只需要需要使用不同的type和资源组合即可,代码如下:

静态照片 - Photo


PHAssetCreationRequest *imageRequest = [PHAssetCreationRequest creationRequestForAsset];
[imageRequest addResourceWithType:PHAssetResourceTypePhoto data:imageData options:nil];

PS:可以使用可以将需要保存UIImage通过UIImageJPEGRepresentationUIImagePNGRepresentation方法转成需要的imageData

动态照片 - Photo + PairedVideo


PHAssetCreationRequest* creationRequest = [PHAssetCreationRequest creationRequestForAsset];
[creationRequest addResourceWithType:PHAssetResourceTypePhoto data:imageData options:nil];
PHAssetResourceCreationOptions* resourceOptions = [[PHAssetResourceCreationOptions alloc] init];
resourceOptions.shouldMoveFile = YES;
[creationRequest addResourceWithType:PHAssetResourceTypePairedVideo fileURL:filmURL options:resourceOptions];

PS:动态照片的视频部分类型必须是PHAssetResourceTypePairedVideo表示该视频是整个资源的一部分,那么系统将会将其与同时传入的照片一起合成动态照片。

视频 - Video


PHAssetCreationRequest *videoRequest = [PHAssetCreationRequest creationRequestForAsset];
PHAssetResourceCreationOptions* resourceOptions = [[PHAssetResourceCreationOptions alloc] init];
resourceOptions.shouldMoveFile = YES;
[videoRequest addResourceWithType:PHAssetResourceTypeVideo fileURL:fileURL options:resourceOptions];

PS:这里和动态照片中的视频一样都使用了options,它是一个PHAssetResourceCreationOptions对象,可用于定义存入文件的文件名(originalFilename)、文件类型(uniformTypeIdentifier)和是否在写入后删除(shouldMoveFile)。

组合操作

由于将资源写入相册需要权限,因此每次在写入的时候我们都应该像下方的代码一样先处理权限问题,再处理写入问题:


+ (void)customSaveWithChangeBlock:(dispatch_block_t)changeBlock
                        authHandle:(SCPhotosSaveAuthHandle)authHandle
                       completion:(SCPhotosSaveCompletion)completion {
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        if (status != PHAuthorizationStatusAuthorized) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (authHandle)
                    authHandle(false, status);
            });
            return;
        }
        [[PHPhotoLibrary sharedPhotoLibrary]
         performChanges: changeBlock
         completionHandler:^(BOOL success, NSError * _Nullable error) {
             dispatch_async(dispatch_get_main_queue(), ^{
                 if (completion)
                     completion(success, error);
             });
         }];
    }];
}

最后:我将文章中三种媒体类型的保存方式都封装在分类中,大家可以直接查阅PHPhotoLibrary+Save.h进行使用。