一、为什么要获取权限
在越来越注重个人隐私的今天,用户很多情况下希望自己能完全掌握自己手机应用对媒体信息的一些访问权限,比如相册、相机、通讯录等。苹果在iOS7、iOS8等几个系统版本对一些权限的控制都做了加强,需要用户授权后应用才有相关的访问权限。
场景:
在你获取相册数据的时候,如果用户拒绝授权,那么可能会获取不到数据,此时需要给用户相应的提示,告知用户是权限的问题,此时,就需要得知相应的权限状态给用户恰当的提示。
用户的设备没有相机输入设备,如果你想访问用户的相机,此时就需要判断用户设备是否支持,给出恰当的提示。
二、权限状态说明
-
相册、相机、通讯录等授权状态目前都有种,都可以对应以下几种状态:
AuthorizationStatusNotDetermined // 用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权 AuthorizationStatusAuthorized = 0, // 用户已授权,允许访问 AuthorizationStatusDenied, // 用户拒绝访问 AuthorizationStatusRestricted, // 应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制
三、权限获取
- 相册权限
-
是否支持
``` [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] ```
-
获取权限状态
ios8以前 ``` ALAuthorizationStatus authStatus = [ALAssetsLibrary authorizationStatus]; ``` ios8及以后 ``` PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus]; ```
-
请求权限
``` [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { }]; ```
-
权限状态
iOS8以前 ``` typedef NS_ENUM(NSInteger, ALAuthorizationStatus) { ALAuthorizationStatusNotDetermined NS_ENUM_DEPRECATED_IOS(6_0, 9_0) = 0, // User has not yet made a choice with regards to this application ALAuthorizationStatusRestricted NS_ENUM_DEPRECATED_IOS(6_0, 9_0), // This application is not authorized to access photo data. // The user cannot change this application’s status, possibly due to active restrictions // such as parental controls being in place. ALAuthorizationStatusDenied NS_ENUM_DEPRECATED_IOS(6_0, 9_0), // User has explicitly denied this application access to photos data. ALAuthorizationStatusAuthorized NS_ENUM_DEPRECATED_IOS(6_0, 9_0) // User has authorized this application to access photos data. } NS_DEPRECATED_IOS(6_0, 9_0, "Use PHAuthorizationStatus in the Photos framework instead"); ``` iOS8及以后 ``` typedef NS_ENUM(NSInteger, PHAuthorizationStatus) { PHAuthorizationStatusNotDetermined = 0, // User has not yet made a choice with regards to this application PHAuthorizationStatusRestricted, // This application is not authorized to access photo data. // The user cannot change this application’s status, possibly due to active restrictions // such as parental controls being in place. PHAuthorizationStatusDenied, // User has explicitly denied this application access to photos data. PHAuthorizationStatusAuthorized // User has authorized this application to access photos data. } NS_AVAILABLE_IOS(8_0); ```
- 拍照权限
-
是否支持
``` [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] ```
-
获取权限状态
``` AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; ```
-
请求权限
``` [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { }]; ```
-
权限状态
``` typedef NS_ENUM(NSInteger, AVAuthorizationStatus) { AVAuthorizationStatusNotDetermined = 0, AVAuthorizationStatusRestricted, AVAuthorizationStatusDenied, AVAuthorizationStatusAuthorized } NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; ```
- 通讯录权限
-
获取权限状态
iOS9以前 ``` ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus(); ``` iOS9及以后 ``` CNAuthorizationStatus authStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; ```
-
请求权限
iOS9以前 ``` __block ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); if (addressBook == NULL) { [self executeCallback:callback status:WTAuthorizationStatusNotSupport]; return; } ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (granted) { // 成功 } else { // 失败 } if (addressBook) { CFRelease(addressBook); addressBook = NULL; } }); ``` iOS9及以后 ``` CNContactStore *contactStore = [[CNContactStore alloc] init]; [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted) { // 成功 } else { // 失败 } }]; ```
-
权限状态
iOS9以前 ``` typedef CF_ENUM(CFIndex, ABAuthorizationStatus) { kABAuthorizationStatusNotDetermined = 0, // deprecated, use CNAuthorizationStatusNotDetermined kABAuthorizationStatusRestricted, // deprecated, use CNAuthorizationStatusRestricted kABAuthorizationStatusDenied, // deprecated, use CNAuthorizationStatusDenied kABAuthorizationStatusAuthorized // deprecated, use CNAuthorizationStatusAuthorized } AB_DEPRECATED("use CNAuthorizationStatus"); ``` iOS9及以后 ``` typedef NS_ENUM(NSInteger, CNAuthorizationStatus)
{
/*! The user has not yet made a choice regarding whether the application may access contact data. /
CNAuthorizationStatusNotDetermined = 0,
/! The application is not authorized to access contact data.
* The user cannot change this application’s status, possibly due to active restrictions such as parental controls being in place. /
CNAuthorizationStatusRestricted,
/! The user explicitly denied access to contact data for the application. /
CNAuthorizationStatusDenied,
/! The application is authorized to access contact data. */
CNAuthorizationStatusAuthorized
} NS_ENUM_AVAILABLE(10_11, 9_0);
```
四、拒绝授权的处理
-
用户拒绝授权后,如果访问相应内容可能会出现一些类似没有数据的情况,此时应该给用户提示,引导用户授权。
跳转到应用设置:
NSURL *settingUrl = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; if ([[UIApplication sharedApplication] canOpenURL:settingUrl]) { [[UIApplication sharedApplication] openURL:settingUrl]; }
五、简单封装示例
-
工具类
WTAuthorizationTool.h文件
#import <Foundation/Foundation.h> typedef NS_ENUM(NSUInteger, WTAuthorizationStatus) { WTAuthorizationStatusAuthorized = 0, // 已授权 WTAuthorizationStatusDenied, // 拒绝 WTAuthorizationStatusRestricted, // 应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制 WTAuthorizationStatusNotSupport // 硬件等不支持 }; @interface WTAuthorizationTool : NSObject /** * 请求相册访问权限 * * @param callback <#callback description#> */ + (void)requestImagePickerAuthorization:(void(^)(WTAuthorizationStatus status))callback; /** * 请求相机权限 * * @param callback <#callback description#> */ + (void)requestCameraAuthorization:(void(^)(WTAuthorizationStatus status))callback; + (void)requestAddressBookAuthorization:(void (^)(WTAuthorizationStatus))callback; @end
WTAuthorizationTool.m文件
#import "WTAuthorizationTool.h" #import <AssetsLibrary/AssetsLibrary.h> #import <Photos/Photos.h> #import <AddressBook/AddressBook.h> #import <AddressBookUI/AddressBookUI.h> #import <ContactsUI/ContactsUI.h> @implementation WTAuthorizationTool #pragma mark - 相册 + (void)requestImagePickerAuthorization:(void(^)(WTAuthorizationStatus status))callback { if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] || [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { ALAuthorizationStatus authStatus = [ALAssetsLibrary authorizationStatus]; if (authStatus == ALAuthorizationStatusNotDetermined) { // 未授权 if ([UIDevice currentDevice].systemVersion.floatValue < 8.0) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else if (status == PHAuthorizationStatusDenied) { [self executeCallback:callback status:WTAuthorizationStatusDenied]; } else if (status == PHAuthorizationStatusRestricted) { [self executeCallback:callback status:WTAuthorizationStatusRestricted]; } }]; } } else if (authStatus == ALAuthorizationStatusAuthorized) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else if (authStatus == ALAuthorizationStatusDenied) { [self executeCallback:callback status:WTAuthorizationStatusDenied]; } else if (authStatus == ALAuthorizationStatusRestricted) { [self executeCallback:callback status:WTAuthorizationStatusRestricted]; } } else { [self executeCallback:callback status:WTAuthorizationStatusNotSupport]; } } #pragma mark - 相机 + (void)requestCameraAuthorization:(void (^)(WTAuthorizationStatus))callback { if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (authStatus == AVAuthorizationStatusNotDetermined) { [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { if (granted) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else { [self executeCallback:callback status:WTAuthorizationStatusDenied]; } }]; } else if (authStatus == AVAuthorizationStatusAuthorized) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else if (authStatus == AVAuthorizationStatusDenied) { [self executeCallback:callback status:WTAuthorizationStatusDenied]; } else if (authStatus == AVAuthorizationStatusRestricted) { [self executeCallback:callback status:WTAuthorizationStatusRestricted]; } } else { [self executeCallback:callback status:WTAuthorizationStatusNotSupport]; } } #pragma mark - 通讯录 + (void)requestAddressBookAuthorization:(void (^)(WTAuthorizationStatus))callback { ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus(); if (authStatus == kABAuthorizationStatusNotDetermined) { __block ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); if (addressBook == NULL) { [self executeCallback:callback status:WTAuthorizationStatusNotSupport]; return; } ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (granted) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else { [self executeCallback:callback status:WTAuthorizationStatusDenied]; } if (addressBook) { CFRelease(addressBook); addressBook = NULL; } }); return; } else if (authStatus == kABAuthorizationStatusAuthorized) { [self executeCallback:callback status:WTAuthorizationStatusAuthorized]; } else if (authStatus == kABAuthorizationStatusDenied) { [self executeCallback:callback status:WTAuthorizationStatusDenied]; } else if (authStatus == kABAuthorizationStatusRestricted) { [self executeCallback:callback status:WTAuthorizationStatusRestricted]; } } #pragma mark - callback + (void)executeCallback:(void (^)(WTAuthorizationStatus))callback status:(WTAuthorizationStatus)status { dispatch_async(dispatch_get_main_queue(), ^{ if (callback) { callback(status); } }); } @end
-
界面测试提示
controller部分代码
- (void)requestAddressBook { [WTAuthorizationTool requestAddressBookAuthorization:^(WTAuthorizationStatus status) { [self requestAuthCallback:status]; }]; } - (void)requestCamera { [WTAuthorizationTool requestCameraAuthorization:^(WTAuthorizationStatus status) { [self requestAuthCallback:status]; }]; } - (void)requestAlbum { [WTAuthorizationTool requestImagePickerAuthorization:^(WTAuthorizationStatus status) { [self requestAuthCallback:status]; }]; } - (void)requestAuthCallback:(WTAuthorizationStatus)status { switch (status) { case WTAuthorizationStatusAuthorized: [WTAlert showAlertFrom:self title:@"授权成功" message:@"可以访问你要访问的内容了" cancelButtonTitle:@"我知道了" cancle:^{ } confirmButtonTitle:nil confirm:nil]; break; case WTAuthorizationStatusDenied: case WTAuthorizationStatusRestricted: [WTAlert showAlertFrom:self title:@"授权失败" message:@"用户拒绝" cancelButtonTitle:@"我知道了" cancle:^{ } confirmButtonTitle:@"现在设置" confirm:^{ NSURL *settingUrl = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; if ([[UIApplication sharedApplication] canOpenURL:settingUrl]) { [[UIApplication sharedApplication] openURL:settingUrl]; } }]; break; case WTAuthorizationStatusNotSupport: [WTAlert showAlertFrom:self title:@"授权失败" message:@"设备不支持" cancelButtonTitle:@"我知道了" cancle:^{ } confirmButtonTitle:nil confirm:nil]; default: break; } }
六、源码
-
使用WTAuthorizationTool
pod "WTAuthorizationTool"