IOS调用系统相机时,didFinishPickingMediaWithInfo获取不到Asset

今天本来想做服务器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];
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。