一、為什么要獲取權限
在越來越注重個人隱私的今天,用戶很多情況下希望自己能完全掌握自己手機應用對媒體信息的一些訪問權限,比如相冊、相機、通訊錄等。蘋果在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"