【IOS】权限管理

作者: 雨影 | 来源:发表于2017-05-27 14:05 被阅读373次

一个 APP 需要使用各种权限,比如相机,相册,位置等等,一般情况下我们习惯用到的时候,就去判断权限然后调用系统的设备来使用.这样也符合苹果的安全特点.

但是,让我们在编程过程中,会发现,如果事先不知道是否已经请求过权限了,那么就需要在使用之前先判断是否有权限,判断完成之后,等待用户赋予权限,然后继续执行.

拿通讯录举例来说,假设我们要打开系统的通讯录列表,要这么写

   CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
    
    //等待授权状态
    if (status == CNAuthorizationStatusNotDetermined) {
        
        CNContactStore *store = [[CNContactStore alloc] init];
        [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError*  _Nullable error) {
            granted?[self openContact]:[JDMessageView showMessage:@"无法读取通讯录"];
        }];
        
    }
    
    //应用程序未被授权访问联系人数据。*用户不能更改该应用程序的状态,可能由于活跃的限制,如家长控制
    else
    {
        if(status == CNAuthorizationStatusRestricted)
            
            [JDMessageView showMessage:@"无权访问"];
        
        /* !明确拒绝用户访问联系人数据的应用程序。*/
        else if (status == CNAuthorizationStatusDenied)
            
            [JDMessageView showMessage:@"无访问权限"];
        
        else if (status == CNAuthorizationStatusAuthorized)
            
           [self openContact];
        
    }

打开系统通讯录列表方法

- (void)openContact
{
    CNContactPickerViewController *pickerVC =[[CNContactPickerViewController alloc] init];
    pickerVC.delegate = self;
    [self presentViewController:pickerVC animated:YES completion:nil];
}

如果我们要在写一个获取通讯录列表的方法,那么必须要在写这样一个方法

    CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
    
    //等待授权状态
    if (status == CNAuthorizationStatusNotDetermined) {
        
        CNContactStore *store = [[CNContactStore alloc] init];
        [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError*  _Nullable error) {
            granted?[self getContactsArrayList]):[JDMessageView showMessage:@"无法读取通讯录"];
        }];
        
    }
    /*
     !应用程序未被授权访问联系人数据。*用户不能更改该应用程序的状态,可能由于活跃的限制,如家长控制。
     */
    else
    {
        if(status == CNAuthorizationStatusRestricted)
            
            [JDMessageView showMessage:@"无权访问"];
        
        /* !明确拒绝用户访问联系人数据的应用程序。*/
        else if (status == CNAuthorizationStatusDenied)
            
            [JDMessageView showMessage:@"无访问权限"];
        
        else if (status == CNAuthorizationStatusAuthorized)
            
          [self getContactsArrayList];
        
    }
    

有人说这两个方法,完全可以通过一个标志简化下代码,这样写:

    BOOL isSystemUI ;//是否是打开系统通讯录页面
    CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
    
    //等待授权状态
    if (status == CNAuthorizationStatusNotDetermined) {
        
        CNContactStore *store = [[CNContactStore alloc] init];
        [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError*  _Nullable error) {
            granted?(_isSystemUI?[self openContact]:[self getContactsArrayList]):[JDMessageView showMessage:@"无法读取通讯录"];
        }];
        
    }
    /*
     !应用程序未被授权访问联系人数据。*用户不能更改该应用程序的状态,可能由于活跃的限制,如家长控制。
     */
    else
    {
        if(status == CNAuthorizationStatusRestricted)
            
            [JDMessageView showMessage:@"无权访问"];
        
        /* !明确拒绝用户访问联系人数据的应用程序。*/
        else if (status == CNAuthorizationStatusDenied)
            
            [JDMessageView showMessage:@"无访问权限"];
        
        else if (status == CNAuthorizationStatusAuthorized)
            
            _isSystemUI?[self openContact]:[self getContactsArrayList];
        
    }
    

但是假如我又加一个添加联系人方法呢?因为你无法判断他是需要先看列表还是先添加联系人,所以你就必须每次都得判断一下权限.这对于我们变成和封装方法是一个非常痛苦的.

所以很多 APP 都采用,第一次安装就把各种权限请求一遍的策略.我觉得就是为了两点:

1.减少请求用户的骚扰,一步到位.
2.简化代码,让代码出错率降低.

因此我们可以建这样一个类:
.h 文件

@interface JDAuthorityManager : NSObject
/**
 请求 APP 需要的权限
 */
+ (void)requestAuthority;

@end

.m 文件

#import "JDAuthorityManager.h"
#import <AVFoundation/AVFoundation.h>   //相机
#import <Photos/Photos.h>               //相册
#import <CoreLocation/CoreLocation.h>   //定位
#import <AddressBook/AddressBook.h>     //通讯录

static NSString *authorityStr =@"authority";

@implementation JDAuthorityManager


+ (void)requestAuthority{
    
    //只请求一次
    NSUserDefaults *defaut =[NSUserDefaults standardUserDefaults];
    NSString *authority = [defaut objectForKey:authorityStr];
    if (authority) {
        return;
    }
    [defaut setObject:@"authority" forKey:authorityStr];
    
    
    //相册权限
    PHAuthorizationStatus photoAuthorStatus = [PHPhotoLibrary authorizationStatus];
    if (photoAuthorStatus == PHAuthorizationStatusNotDetermined){
        
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            
        }];
    }
    //相机
    AVAuthorizationStatus avstatus =[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (avstatus == AVAuthorizationStatusNotDetermined) {
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            
        }];
    }
    //麦克风
    AVAuthorizationStatus micstatus =[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    if (micstatus == AVAuthorizationStatusNotDetermined) {
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
            
        }];
    }
    
    //定位权限
    CLAuthorizationStatus cLstatus = [CLLocationManager authorizationStatus];
    if (cLstatus == kCLAuthorizationStatusNotDetermined) {
        
        [[[CLLocationManager alloc]init] requestWhenInUseAuthorization];
        [[[CLLocationManager alloc]init] requestAlwaysAuthorization];
        
    }
    
    //通讯录 ios9之前
    ABAuthorizationStatus abstatus =ABAddressBookGetAuthorizationStatus();
    if (abstatus  == kABAuthorizationStatusNotDetermined) {
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            
        });
    }
    
    //日历或者备忘录
}

@end

然后在 appdelegate 中调用一下.

假设我们事先已经请求过权限了,前面的方法就可以简化为

    CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
    if (status == CNAuthorizationStatusAuthorized)
    {
        [self openContact]
    }
    else
    {
        //无权限
    }

是不是麻烦的权限问题迎刃而解?

Demo地址:https://github.com/yuying2012/WJDStudyLibrary
这是一个大工程,请从工程中寻找相关模块代码.

相关文章

网友评论

    本文标题:【IOS】权限管理

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