1. 程式人生 > >iOS相簿、相機、通訊錄許可權獲取

iOS相簿、相機、通訊錄許可權獲取

一、為什麼要獲取許可權

在越來越注重個人隱私的今天,使用者很多情況下希望自己能完全掌握自己手機應用對媒體資訊的一些訪問許可權,比如相簿、相機、通訊錄等。蘋果在iOS7、iOS8等幾個系統版本對一些許可權的控制都做了加強,需要使用者授權後應用才有相關的訪問許可權。

場景:

  • 在你獲取相簿資料的時候,如果使用者拒絕授權,那麼可能會獲取不到資料,此時需要給使用者相應的提示,告知使用者是許可權的問題,此時,就需要得知相應的許可權狀態給使用者恰當的提示。

  • 使用者的裝置沒有相機輸入裝置,如果你想訪問使用者的相機,此時就需要判斷使用者裝置是否支援,給出恰當的提示。

二、許可權狀態說明

  • 相簿、相機、通訊錄等授權狀態目前都有種,都可以對應以下幾種狀態:

    AuthorizationStatusNotDetermined      // 使用者從未進行過授權等處理,首次訪問相應內容會提示使用者進行授權
    AuthorizationStatusAuthorized = 0,    // 使用者已授權,允許訪問
    AuthorizationStatusDenied,            // 使用者拒絕訪問
    AuthorizationStatusRestricted,        // 應用沒有相關許可權,且當前使用者無法改變這個許可權,比如:家長控制

三、許可權獲取

  1. 相簿許可權

    • 是否支援

      [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);
  2. 拍照許可權

    • 是否支援

      [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;
  3. 通訊錄許可權

    • 獲取許可權狀態

      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"