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)当只是要开关某个权限的时候,进入设置-->隐私 里面开关即可。

时间: 2024-08-05 11:18:20

iOS开发实战——摄像头与相册权限获取逻辑优化的相关文章

iOS开发-检测用户截屏, 并获取所截图片

微信可以检测到用户截屏行为(Home + Power),并在稍后点击附加功能按钮时询问用户是否要发送刚才截屏的图片,这个用户体验非常好.于是乎, 我也想着实现这个功能. 在iOS7之前, 如果用户截屏,系统会自动取消屏幕上的所有 touch 事件,(使用 touchesCancelled:withEvent: 这个方法)那么我们就可以检测这个方法的调用,然后加载本地最新图片再加以判断来实现我们的目的.但在 iOS 7 之后,截屏不再会取消屏幕的 touch 事件,所以导致了 Snapchat 和

iOS开发实战——CollectionView中cell的间距设置

我在前面多篇博客中详细讲解了CollectionView的使用与自定义CollectionViewCell的设计,可以参考<iOS开发实战--CollectionView点击事件与键盘隐藏结合案例><iOS高级开发--CollectionView修改cell的文本及模型重构>这几篇博客.但是今天还是需要来讲讲CollectionView实现中的一个小小的坑,这是我最近在网上浏览时发现很多开发者经常犯的错,所以我觉得有必要来好好谈一谈. 一个CollectionView控件中,两个c

iOS开发——实战OC篇&amp;环境搭建之Xib(玩转UINavigationController与UITabBarController)

iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController) 前面我们介绍了StoryBoard这个新技术,和纯技术编程的代码创建界面,本篇我们将介绍一个老的技术,但是在很多的公司或者库里面还是使用这个技术,既然如此它肯定有他的好处,至于好处这里我就不一一介绍了.在Xcode5之前是只能使用Xib或者代码的,而代码又对于很多初学者来说算是一个难题.毕竟不知道怎么下手.所以我就总结了一下这段时间自己编写程序的一个实例来说明怎么

iOS开发——实战OC篇&amp;环境搭建之纯代码(玩转UINavigationController与UITabBarController)

iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController) 这里我们就直接上实例: 一:新建一个项目singleView Controller,命名未iCocos 二:由于我们使用的纯代码实现的,所以删除其中的StoryBoard和Viewtroller的两个文件 三:新建一个继承自TabBar Controller的类,我们命名问iCocos ViewController 三:在Appdelegate的实现文件中导入刚刚

iOS开发实战——CollectionView点击事件与键盘隐藏结合案例(二)

我在前一篇博客中<iOS开发实战--CollectionView点击事件与键盘隐藏结合案例>详细实现了CollectionView与键盘组合操作中出现的多种情况,并解决了交互体验上的一些问题.在实际项目中也的确可以采用这种方法来操作.但是问题来了,原来的界面我们是使用UIView来操作的,也就是界面是不可滚动的.然而更为常见的场景是一个ScrollView,界面可以进行上下滚动.所以,这篇博客主要是对前一个案例进行优化.还有一个问题是,在自动布局Masonry结合ScrollView中,会碰到

Xamarin iOS开发实战上册-----2.2.2 使用代码添加视图

Xamarin iOS开发实战上册-----2.2.2  使用代码添加视图 如果开发者想要使用代码为主视图添加视图,该怎么办呢.以下将为开发者解决这一问题.要使用代码为主视图添加视图需要实现3个步骤. 1.实例化视图对象 每一个视图都是一个特定的类.在C#中,经常会说,类是一个抽象的概念,而非具体的事物,所以要将类进行实例化.实例化一个视图对象的具体语法如下: 视图类 对象名=new 视图类(); 以我们接触的第一个视图View为例,它的实例化对象如下: UIView vv=new UIView

Xamarin iOS开发实战第1章使用C#编写第一个iOS应用程序

Xamarin iOS开发实战第1章使用C#编写第一个iOS应用程序 C#原本是用来编写Windows以及Windows Phone的应用程序.自从Xamarin问世后,C#的作用就发生了很大的变化.它不仅可以编写关于Windows以及Windowsx Phone的应用程序,还可以编写iOS.Android的应用程序.本章将讲解如何使用C#编写一个简单的iOS应用程序.本文选自<Xamarin iOS开发实战> 1.1初识Xamarin Xamarin是一个跨平台的开发框架.Xamarin的产

Xamarin iOS开发实战1.1.3Xamarin版本

Xamarin iOS开发实战1.1.3Xamarin版本 Xamarin提供了免费版和付费版.免费版本包含Xamarin Studio服务.付费版本分为普通版299美元/年.商业版999美元/年和企业版1899美元/年.开发者可以根据自身需要进行购买,如图1.1所示.本文选自Xamarin iOS开发实战大学霸 图1.1  Xamarin各个版本 注意:针对学生及研究人员,Xamarin提供以99美元/年的价格购买商业版授权. 1.1.4  工具需求 要使用C#编写iOS应用程序,需要使用到3

Xamarin iOS开发实战上册 (内部资料)

试读样章下载地址:http://pan.baidu.com/s/1mgqQIxE 前  言 由于iOS全新的界面设计.极高的用户体验度.丰富的软件,成为最受欢迎的智能设备.同时,苹果公司具备完善的App Store模式,广受程序员了解和认可.虽然苹果官方推荐使用Objective-C和Swift进行开发,但也允许其他语言开发的软件进入Apple Store. 而C#+Xamarin是现在广为流行的开发模式.其中,Xamarin是一款跨平台的开发框架.使用Xamarin可以开发iOS.Androi