iOS开发实战——摄像头与相册权限获取逻辑优化
Posted 乞力马扎罗的雪CYF
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发实战——摄像头与相册权限获取逻辑优化相关的知识,希望对你有一定的参考价值。
在实际项目中,我们经常需要访问设备的摄像头或者相册,当第一次安装某个App的时候,系统便会弹出授权对话框,要求用户做出是否授权的判断。整体逻辑比较简单,但是在使用过程中需要对用户体验进行优化,否则会出现bug。该博客的示例代码已经上传至 https://github.com/chenyufeng1991/AuthorityOfCameraAndPhoto 。
首先我先描述一下出现的问题。我以访问相册为例,实现代码如下:
- (void)photoBtnPressed:(id)sender
{
// 首先查看当前设备是否支持相册
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{
[self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary];
}
else
{
[self showAlertController:@"提示" message:@"当前设备不支持相册"];
}
}
- (void)presentToImagePickerController:(UIImagePickerControllerSourceType)type
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = type;
[self presentViewController:picker animated:YES completion:nil];
}
- (void)showAlertController:(NSString *)title message:(NSString *)message
{
UIAlertController *ac = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[ac addAction:[UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}]];
[self presentViewController:ac animated:YES completion:nil];
}
解释一下,首先需要判断当前设备是否支持相册,进行这样判断操作会比较安全。如果可以的话直接使用UIImagePickerController访问,否则弹出alert提示框。第一次运行效果如下:
。
该对话框就是系统请求用户获得访问相册权限的对话框,如果点击“OK”,那么就能弹出相册界面。如果点击"Don't Allow",用户就无法访问相册,因为我这里要演示交互问题,所以我点击"Don't Allow".此时出现如下的空白界面:
。
这样就会出现交互问题,跳到了一个完全空白的页面,并且没有任何的提示,准确来说,这就是一个bug。而且我们无法对这个空白页面进行自定义。如果大家仔细观察这个权限获得的过程,发现界面是首先弹出这个空白页面,然后才是弹出选择对话框。这就是问题所在,获取摄像头权限也是一样的,下面我们就来解决这类问题。
我的目标是首先弹出授权对话框,如果我允许授权,那么就跳到摄像头界面或者相册界面;如果我拒绝授权,那么就跳到一个带有提示的自定义页面。首先以相册为例来实现:
(1)首先说明下授权状态,共有三种:
已授权:***Authorized;
未确定:***NotDetrmined;
已拒绝:***Denied,***Restricted;
对于当前设备的这些权限状态,我们可以直接读取,我实现了以下方法:
+ (BOOL)isPhotoAlbumDenied
{
ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];
if (author == ALAuthorizationStatusRestricted || author == ALAuthorizationStatusDenied)
{
return YES;
}
return NO;
}
+ (BOOL)isPhotoAlbumNotDetermined
{
ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];
if (author == ALAuthorizationStatusNotDetermined)
{
return YES;
}
return NO;
}
isPhotoAlbumDenied方法判断相册权限是否已经被拒绝;isPhotoAlbumNotDetermined方法判断是否还没确定。方法接口写在YFKit类中。
(2)授权方法实现如下:
- (void)optimalPhotoBtnPressed:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{
// 第一次安装App,还未确定权限,调用这里
if ([YFKit isPhotoAlbumNotDetermined])
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
// 该API从ios8.0开始支持
// 系统弹出授权对话框
[phphotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
dispatch_async(dispatch_get_main_queue(), ^{
if (status == PHAuthorizationStatusRestricted || status == PHAuthorizationStatusDenied)
{
// 用户拒绝,跳转到自定义提示页面
DeniedAuthViewController *vc = [[DeniedAuthViewController alloc] init];
[self presentViewController:vc animated:YES completion:nil];
}
else if (status == PHAuthorizationStatusAuthorized)
{
// 用户授权,弹出相册对话框
[self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary];
}
});
}];
}
else
{
// 以上requestAuthorization接口只支持8.0以上,如果App支持7.0及以下,就只能调用这里。
[self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary];
}
}
else if ([YFKit isPhotoAlbumDenied])
{
// 如果已经拒绝,则弹出对话框
[self showAlertController:@"提示" message:@"拒绝访问相册,可去设置隐私里开启"];
}
else
{
// 已经授权,跳转到相册页面
[self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary];
}
}
else
{
// 当前设备不支持打开相册
[self showAlertController:@"提示" message:@"当前设备不支持相册"];
}
}
(3)运行效果如下:
申请授权:
。
可以看到此时是先弹出对话框进行确认的,而不是跳到相册空白页面才进行弹出确认的。
拒绝授权:
。
该空态界面可以自定义。
允许授权:
。
直接跳到相册页面了。
(3)摄像头申请授权逻辑与相册类似,只是使用的API不同,但是更为简单,因为该API可以支持7.0及以上,而目前的App都基本支持7.0及以上。使用的接口是AVCaptureDevice。实现方法如下:
- (void)optimalCameraBtnPressed:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
// 应用第一次申请权限调用这里
if ([YFKit isCameraNotDetermined])
{
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
dispatch_async(dispatch_get_main_queue(), ^{
if (granted)
{
// 用户授权
[self presentToImagePickerController:UIImagePickerControllerSourceTypeCamera];
}
else
{
// 用户拒绝授权
DeniedAuthViewController *vc = [[DeniedAuthViewController alloc] init];
[self presentViewController:vc animated:YES completion:nil];
}
});
}];
}
// 用户已经拒绝访问摄像头
else if ([YFKit isCameraDenied])
{
[self showAlertController:@"提示" message:@"拒绝访问摄像头,可去设置隐私里开启"];
}
// 用户允许访问摄像头
else
{
[self presentToImagePickerController:UIImagePickerControllerSourceTypeCamera];
}
}
else
{
// 当前设备不支持摄像头,比如模拟器
[self showAlertController:@"提示" message:@"当前设备不支持拍照"];
}
}
测试摄像头需要在真机下进行测试,因为模拟器不支持摄像头。
通过以上代码,可以有效并且可控的进行摄像头和相册权限申请的流程控制,优化用户体验。下面给出一些开发tips:
(1)对于模拟器,如果想要重置应用的权限与隐私设置,可以直接重置模拟器,选择Simulator-->Reset Content and Setting即可。下次重新安装App时,所有的权限都要重新申请了。
(2)在真机上重置权限可以进入:设置-->通用-->重置-->重置位置与隐私即可。这种重置方式是安全的,不会导致手机上的其他数据的丢失,仅仅只是把某些权限记录给删除了。当需要使用权限的时候,系统会重新申请。
(3)当只是要开关某个权限的时候,进入设置-->隐私 里面开关即可。
以上是关于iOS开发实战——摄像头与相册权限获取逻辑优化的主要内容,如果未能解决你的问题,请参考以下文章
NR - iOS / Android 相机/相册/日历/定位 等权限 检测+申请代码
NR - iOS / Android 相机/相册/日历/定位 等权限 检测+申请代码