美文网首页iOS相机和相册相关专题
IOS调用系统相机时,didFinishPickingMedia

IOS调用系统相机时,didFinishPickingMedia

作者: 涛涛涛涛涛涛涛涛涛 | 来源:发表于2019-07-17 22:46 被阅读0次

    今天本来想做服务器SSL证书部署的,但是项目发现了一个问题没时间去做了,晚上剩一点点时间就把这个问题记录一下。

    当调用系统相机时,在imagePickerController回调时会获取不到Asset。
    在didFinishPickingMediaWithInfo里可以直接拿到image对象,一般情况下直接返回image就可以了,根本不需要用到Asset,所以我对Asset也并不是非常了解。
    原来的代码里Asset主要用来获取图片的原始Data并返回,由于代码不规范,当Asset为空时就没有回调了,所以才能够发现这个问题。

    由于之前用的是ALAssetsLibrary,当时还以为是因为ALAssetsLibrary被废弃而造成的BUG。但是当我将ALAssetsLibrary替换成<Photos/Photos.h>时,这个问题仍然存在。

    当我查了一遍度娘后,我猜测:
    1、Asset是相当于相册中的图片的资源文件或者能标记对应图片的标识文件。
    2、在使用相机拍摄后,当点击“使用照片”按钮时,图片并没有存在相册里,所以就没有生成对应的资源文件。

    所以当点击"使用照片",触发了imagePickerController的didFinishPickingMediaWithInfo方法时,无法获取Asset。

    经过尝试,只需要在didFinishPickingMediaWithInfo方法中判断Asset,如果Asset为nil则将图片储存,然后再进行一次获取Asset的操作。

    #pragma mark - FinishPick -选择照片回调
    -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info
    {
        WS(weakSelf);
        [picker dismissViewControllerAnimated:YES completion:nil];
        UIImage * image = [[UIImage alloc]init];
        __block PHAsset *phAsset = [[PHAsset alloc]init];
        image = [info valueForKey:UIImagePickerControllerOriginalImage];
        phAsset = [self getPHAssetWithInfo:info LocalIdentifier:nil];
        if (phAsset == nil) {
            [self saveImage_Obj:image completion:^(BOOL success, NSError * _Nullable error, NSString * _Nullable localIdentifier) {
                if (success) {
                    phAsset = [self getPHAssetWithInfo:info LocalIdentifier:localIdentifier];
                }
                if (!success || phAsset == nil) {
                    if (weakSelf.getPickImage != nil) {
                        weakSelf.getPickImage(image,nil);
                    }
                    return;
                }
                [self getImageData:phAsset completion:^(NSData *imageData) {
                    if (weakSelf.getPickImage != nil) {
                        weakSelf.getPickImage(image,imageData);
                    }
                }];
            }];
        }
        else
        {
            [self getImageData:phAsset completion:^(NSData *imageData) {
                if (weakSelf.getPickImage != nil) {
                    weakSelf.getPickImage(image,imageData);
                }
            }];
        }
    }
    
    #pragma mark - 获取PHAsset
    -(PHAsset *)getPHAssetWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info LocalIdentifier:(NSString *)localIdentifier
    {
        PHAsset *phAsset = [[PHAsset alloc]init];
        if (@available(iOS 11.0, *)) {
            phAsset = [info valueForKey:UIImagePickerControllerPHAsset];
        } else {
            // Fallback on earlier versions
            NSURL * imageURL = [info valueForKey:UIImagePickerControllerMediaURL];
            PHFetchResult *fetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil];
            phAsset = fetchResult.firstObject;
            
        }
        return phAsset;
    }
    
    #pragma mark - 获取图片Data
    -(void)getImageData:(PHAsset *)phAsset completion:(nullable void(^)(NSData * imageData))completion
    {
        PHImageRequestOptions * imageRequest = [[PHImageRequestOptions alloc]init];
        imageRequest.version = PHImageRequestOptionsVersionUnadjusted;
        
        [[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:imageRequest resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
            if (completion != nil) {
                completion(imageData);
            }
        }];
    }
    
    #pragma mark - CancelPick -取消选择回调
    -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
    {
        [picker dismissViewControllerAnimated:YES completion:nil];
    }
    

    另外今天把这个系统相册、相机的方法都更新了一下,顺便一起发上来吧~

    #pragma mark - 使用相册
    -(void)UsePhotographAlbum:(GetPickController)getPickController
    {
        UIImagePickerController *pick = [[UIImagePickerController alloc]init];
        pick.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        pick.delegate = self;
        [self checkPHAuthorizationStatusWithAllowToUse:^{
            if (getPickController != nil) {
                getPickController(pick,nil);
            }
        }];
    }
    
    #pragma mark - 使用相机
    -(void)UseCamera:(GetPickController)getPickController
    {
        UIImagePickerController *pick = [[UIImagePickerController alloc]init];
        pick.sourceType = UIImagePickerControllerSourceTypeCamera;
        pick.delegate = self;
        
        [self checkAVAuthorizationStatusWithAllowToUse:^{
            if (getPickController != nil) {
                getPickController(pick,nil);
            }
        }];
    }
    
    #pragma mark - 保存视频
    - (void)saveVideo:(NSURL *)videoUrl
           completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
    {
        WS(weakSelf);
        [self checkPHAuthorizationStatusWithAllowToUse:^{
            [weakSelf saveVideo:videoUrl completion:^(BOOL success, NSError * _Nullable error) {
                if (completion != nil) {
                    completion(success,error);
                }
            }];
        }];
    }
    
    #pragma mark - 保存图片
    - (void)saveImage:(UIImage *)image
           completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
    {
        WS(weakSelf);
        [self checkPHAuthorizationStatusWithAllowToUse:^{
            [weakSelf saveImage_Obj:image completion:^(BOOL success, NSError * _Nullable error, NSString * _Nonnull localIdentifier) {
                if (completion != nil) {
                    completion(success,error);
                }
            }];
        }];
    }
    
    #pragma mark - 保存GIF
    - (void)saveGIF:(NSString *)gifKey
         completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
    {
        WS(weakSelf);
        [self checkPHAuthorizationStatusWithAllowToUse:^{
            NSString * gifPath = [[SDImageCache sharedImageCache] defaultCachePathForKey:gifKey];
            NSURL * gifUrl = gifPath.length>0?[NSURL URLWithString:gifPath]:[NSURL URLWithString:gifKey];
            [weakSelf saveImage_Obj:gifUrl completion:^(BOOL success, NSError * _Nullable error, NSString * _Nonnull localIdentifier) {
                if (completion != nil) {
                    completion(success,error);
                }
            }];
        }];
    }
    
    #pragma mark - 保存图片方法
    -(void)saveImage_Obj:(id)image_Obj
           completion:(nullable void(^)(BOOL success, NSError *__nullable error, NSString *__nullable localIdentifier))completion
    {
        // 1. 获取相片库对象
        PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
        //占位对象
        __block PHObjectPlaceholder * placeholder;
        
        // 2. 调用changeBlock
        [library performChanges:^{
            
            // 2.1 创建一个相册变动请求
            PHAssetCollectionChangeRequest *collectionRequest;
            
            // 2.2 取出指定名称的相册
            PHAssetCollection *assetCollection = [self getCurrentPhotoCollectionWithTitle:collectionName];
            
            // 2.3 判断相册是否存在
            if (assetCollection) {
                // 如果存在就使用当前的相册创建相册请求
                collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
            } else {
                // 如果不存在, 就创建一个新的相册请求
                collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:collectionName];
            }
            
            // 2.4 根据传入的相片, 创建相片变动请求
            PHAssetChangeRequest *assetRequest;
            if ([image_Obj isKindOfClass:[UIImage class]]) {
                //如果是图片类型
                assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:(UIImage *)image_Obj];
            }
            else if ([image_Obj isKindOfClass:[NSURL class]])
            {
                //如果是URL类型
                assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:(NSURL *)image_Obj];
            }
            else
            {
                completion(NO,nil,nil);
                return;
            }
            
            // 2.4 创建一个占位对象
            placeholder = [assetRequest placeholderForCreatedAsset];
            
            // 2.5 将占位对象添加到相册请求中
            [collectionRequest insertAssets:@[placeholder] atIndexes:[NSIndexSet indexSetWithIndex:0]];
            
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            
            // 3. 回调
            if (completion != nil) {
                completion(success,error,placeholder.localIdentifier);
            }
        }];
    }
    
    #pragma mark - 保存视频方法
    -(void)saveVideoWithURL:(NSURL *)video_Url
              completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
    {
        // 1. 获取相片库对象
        PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
        // 2. 调用changeBlock
        [library performChanges:^{
            
            // 2.1 创建一个相册变动请求
            PHAssetCollectionChangeRequest *collectionRequest;
            
            // 2.2 取出指定名称的相册
            PHAssetCollection *assetCollection = [self getCurrentPhotoCollectionWithTitle:collectionName];
            
            // 2.3 判断相册是否存在
            if (assetCollection) {
                // 如果存在就使用当前的相册创建相册请求
                collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
            } else {
                // 如果不存在, 就创建一个新的相册请求
                collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:collectionName];
            }
            
            // 2.4 根据传入的相片, 创建相片变动请求
            PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:video_Url];
            
            // 2.4 创建一个占位对象
            PHObjectPlaceholder *placeholder = [assetRequest placeholderForCreatedAsset];
            
            // 2.5 将占位对象添加到相册请求中
            [collectionRequest insertAssets:@[placeholder] atIndexes:[NSIndexSet indexSetWithIndex:0]];
            
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            
            // 3. 回调
            if (completion != nil) {
                completion(success,error);
            }
        }];
    }
    
    #pragma mark - 获取相册名称
    -(PHAssetCollection *)getCurrentPhotoCollectionWithTitle:(NSString *)collectionName {
        
        // 1. 创建搜索集合
        PHFetchResult *result = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
        
        // 2. 遍历搜索集合并取出对应的相册
        for (PHAssetCollection *assetCollection in result) {
            
            if ([assetCollection.localizedTitle containsString:collectionName]) {
                return assetCollection;
            }
        }
        
        return nil;
    }
    
    #pragma mark - 检查相册权限
    -(void)checkPHAuthorizationStatusWithAllowToUse:(nullable void(^)(void))allowToUse
    {
        // 1. 获取当前App的相册授权状态
        PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
        
        // 2. 判断授权状态
        if (authorizationStatus == PHAuthorizationStatusAuthorized && allowToUse != nil) {
            allowToUse();
        } else if (authorizationStatus == PHAuthorizationStatusNotDetermined) { // 如果没决定, 弹出指示框, 让用户选择
            
            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
                
                // 如果用户选择授权, 则保存图片
                if (status == PHAuthorizationStatusAuthorized && allowToUse != nil) {
                    allowToUse();
                }
            }];
            
        } else {
            UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"请到设置->隐私->照片中开启【华世界商圈】的对应权限,以便于我们能够存取您的图像信息。" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction * OK_Action = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                if (@available(iOS 10.0, *)) {
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success)
                     {
                         
                     }];
                } else {
                    //iOS10以前,使用旧API
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
                }
            }];
            [alertController addAction:OK_Action];
            
            UIAlertAction * Cancel_Action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                [[AppDelegate lastWindow].viewController.navigationController popViewControllerAnimated:YES];
            }];
            [alertController addAction:Cancel_Action];
            [[AppDelegate lastWindow].rootViewController presentViewController:alertController animated:YES completion:nil];
        }
    }
    
    #pragma mark - 检查相机权限
    -(void)checkAVAuthorizationStatusWithAllowToUse:(nullable void(^)(void))allowToUse
    {
        //判断是否有相机权限
        AVAuthorizationStatus authorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];//读取设备授权状态
        if (authorizationStatus == AVAuthorizationStatusAuthorized && allowToUse != nil) {
            allowToUse();
        }
        else if(authorizationStatus == AVAuthorizationStatusNotDetermined){
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                if (granted == YES && allowToUse != nil) {
                    allowToUse();
                }
            }];
        } else {
            UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"请到设置->隐私->相机中开启【华世界商圈】的使用权限,以便于我们能够使用您的相机进行拍摄或扫描。" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction * OK_Action = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                if (@available(iOS 10.0, *)) {
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success)
                     {
                         
                     }];
                } else {
                    //iOS10以前,使用旧API
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
                }
            }];
            [alertController addAction:OK_Action];
            
            UIAlertAction * Cancel_Action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                [[AppDelegate lastWindow].viewController.navigationController popViewControllerAnimated:YES];
            }];
            [alertController addAction:Cancel_Action];
            [[AppDelegate lastWindow].rootViewController presentViewController:alertController animated:YES completion:nil];
        }
    }
    

    相关文章

      网友评论

        本文标题:IOS调用系统相机时,didFinishPickingMedia

        本文链接:https://www.haomeiwen.com/subject/lprhlctx.html