一个 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
这是一个大工程,请从工程中寻找相关模块代码.