【iOS开发笔记】系统权限的获取和请求

作者: Mr_Ten | 来源:发表于2020-07-14 17:44 被阅读0次

    前言

    iOS开发避免不开系统权限的问题,如何在APP中以更加友好的方式向用户展示系统权限,似乎也是开发过程中指的深思的一件事。

    那如何提高用户获取权限的通过率呢?以下几种方式或许是不错的尝试:

    1.在用户打开app时就向用户请求权限。

    1. 告知用户授权权限后能够获得的好处后再向用户请求权限。

    3.在绝对必要的情况下才向用户请求权限。

    4.在展示系统权限的提示框前,现象用户显示自定义的提示框,如果用户不允许,默认无操作,如果用户允许,再展示系统提示框。

    上面的只是一些尝试,与本文的主要讲述内容关系不大,接下来我们主要来看一下常用的一些系统权限的状态获取以及主动唤起权限请求的方法。

    一、常用的权限及转换枚举

    1 常用的权限

    iOS系统的权限包括很多,本文主要整理了笔者常用的一些权限,后面随着使用可能会继续补充,目前本文中主要包含的权限如下:

    相机权限
    相册权限
    日历权限
    麦克风权限
    推送权限
    定位权限
    提醒事项权限
    通讯录权限
    互联网权限
    蓝牙权限

    2 自定义权限状态枚举

    typedef NS_ENUM(NSInteger, TenAuthorizationStatus) {
        /**未确定*/
        TenAuthorizationStatusNotDetermined = 0,
        /**限制*/
        TenAuthorizationStatusRestricted,
        /**拒绝*/
        TenAuthorizationStatusDenied,
        /**同意授权*/
        TenAuthorizationStatusAuthorized,
    };
    

    二、权限的获取及请求

    1 相机权限

    引入头文件#import <AVFoundation/AVFoundation.h>

    1.1 权限获取

    +(TenAuthorizationStatus)cameraStatue {
        TenAuthorizationStatus status;
        switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) {
            case AVAuthorizationStatusAuthorized:
                status = TenAuthorizationStatusAuthorized;
                break;
            case AVAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case AVAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    1.2 权限请求

    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
    
    }];
    

    2 相机权限

    引入头文件#import <Photos/Photos.h>

    2.1 权限获取

    +(TenAuthorizationStatus)photoLibraryStatus {
        TenAuthorizationStatus status;
        switch ([PHPhotoLibrary authorizationStatus]) {
            case PHAuthorizationStatusAuthorized:
                status = TenAuthorizationStatusAuthorized;
                break;
            case PHAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case PHAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    2.2 权限请求

    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    
    }];
    

    3 日历权限

    引入头文件#import <EventKit/EventKit.h>

    3.1 权限获取

    +(TenAuthorizationStatus)calendarStatus {
        TenAuthorizationStatus status;
        switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]) {
            case EKAuthorizationStatusAuthorized:
                status = TenAuthorizationStatusAuthorized;
                break;
            case EKAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case EKAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    3.2 权限请求

    [[[EKEventStore alloc] init] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
    
    }];
    

    4 麦克风权限

    引入头文件#import <AVFoundation/AVFoundation.h>

    4.1 权限获取

    +(TenAuthorizationStatus)microphoneStatus {
        TenAuthorizationStatus status;
        switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]) {
            case AVAuthorizationStatusAuthorized:
                status = TenAuthorizationStatusAuthorized;
                break;
            case AVAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case AVAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    4.2 权限请求

    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
    
    }];
    

    5 推送权限

    引入头文件#import <UserNotifications/UserNotifications.h>

    5.1 权限获取

    +(TenAuthorizationStatus)pushStatus {
        if (@available(iOS 10.0, *)) {
            dispatch_semaphore_t singal = dispatch_semaphore_create(0);//创建信号量
            __block TenAuthorizationStatus status;
            [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
                switch (settings.authorizationStatus) {
                    case UNAuthorizationStatusDenied:
                        status = TenAuthorizationStatusDenied;
                        break;
                    case UNAuthorizationStatusNotDetermined:
                        status = TenAuthorizationStatusNotDetermined;
                        break;
                    default:
                        status = TenAuthorizationStatusAuthorized;
                        break;
                }
                dispatch_semaphore_signal(singal);//赋值完成发送信号
            }];
            dispatch_semaphore_wait(singal, DISPATCH_TIME_FOREVER);//等待信号
            return status;
        }
        return ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone) ? TenAuthorizationStatusDenied : TenAuthorizationStatusAuthorized;
    }
    

    5.2 权限请求

    if (@available(iOS 10.0, *)) {
      [[UNUserNotificationCenter currentNotificationCenter]requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        
      }];
    }else {
      //iOS10之前,系统对于申请推送权限没有具体的API,只有设置NotificationSettings时,会自动请求权限
      UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge categories:nil];
      [[UIApplication sharedApplication] registerUserNotificationSettings:setting];
    }
    

    6 定位权限

    引入头文件#import <CoreLocation/CoreLocation.h>

    6.1 权限获取

    +(TenAuthorizationStatus)locationStatus {
        if (![CLLocationManager locationServicesEnabled]) {
            //手机定位权限未开启(针对全部应用)
            return TenAuthorizationStatusRestricted;
        }
        TenAuthorizationStatus status;
        switch ([CLLocationManager authorizationStatus]) {
            case kCLAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case kCLAuthorizationStatusDenied:
                status = TenAuthorizationStatusDenied;
                break;
            case kCLAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusAuthorized;
                break;
        }
        return status;
    }
    

    6.2 权限请求

    定位权限请求与其他权限不动,请求的结果是在代理中返回的,可以自己做一层封装,与其他系统权限请求一样用block的形式将结果返回。

    封装方法调用

    [[TenLocationManager shareManager] ten_requestLocationRequest:^(BOOL granted, CLAuthorizationStatus status) {
    
    }];
    

    TenLocationManager.h

    #import <Foundation/Foundation.h>
    #import <CoreLocation/CoreLocation.h>
    
    @interface TenLocationManager : NSObject
    /**单例方法*/
    +(instancetype)shareManager;
    /**
     唤起请求定位权限
     @param block 结果回调
     */
    -(void)ten_requestLocationRequest:(void (^) (BOOL granted, CLAuthorizationStatus status))block;
    @end
    

    TenLocationManager.m

    #import "TenLocationManager.h"
    
    @interface TenLocationManager () <CLLocationManagerDelegate>
    /**请求定位权限结果类*/
    @property (nonatomic, copy) void (^locationAuthBlock) (BOOL granted, CLAuthorizationStatus state);
    /**系统定位*/
    @property (nonatomic, strong) CLLocationManager *sys_locationManager;
    @end
    
    static TenLocationManager *_locationManager;
    @implementation TenLocationManager
    
    /**构造方法*/
    +(instancetype)allocWithZone:(struct _NSZone *)zone {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            if (_locationManager == nil) {
                _locationManager = [super allocWithZone:zone];
            }
        });
        return _locationManager;
    }
    
    /**单例方法*/
    +(instancetype)shareManager {
        return [[self alloc] init];
    }
    
    /**唤起定位权限请求*/
    -(void)ten_requestLocationRequest:(void (^)(BOOL, CLAuthorizationStatus))block {
        self.locationAuthBlock = block;
        [self.sys_locationManager requestWhenInUseAuthorization];
    }
    
    #pragma mark - CLLocationManagerDelegate
    -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
        if (self.locationAuthBlock) {
            self.locationAuthBlock(status == kCLAuthorizationStatusAuthorizedWhenInUse, status);
        }
    }
    
    #pragma mark - lazy getter
    -(CLLocationManager *)sys_locationManager {
        if (!_sys_locationManager) {
            _sys_locationManager = [[CLLocationManager alloc]init];
            _sys_locationManager.delegate = self;
        }
        return _sys_locationManager;
    }
    

    7 提醒事项权限

    引入头文件#import <EventKit/EventKit.h>

    7.1 权限获取

    +(TenAuthorizationStatus)remindStatus {
        TenAuthorizationStatus status;
        switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder]) {
            case EKAuthorizationStatusAuthorized:
                status = TenAuthorizationStatusAuthorized;
                break;
            case EKAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case EKAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    7.2 权限请求

    [[[EKEventStore alloc] init] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
    
    }];
    

    8 通讯录权限

    引入头文件
    iOS 9.0前 #import <AddressBook/AddressBook.h>
    iOS 9.0后 #import <Contacts/Contacts.h>

    8.1 权限获取

    +(TenAuthorizationStatus)addressBookStatus {
      TenAuthorizationStatus status;
      if (@available(iOS 9.0, *)) {
        switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) {
          case CNAuthorizationStatusAuthorized:
              status = TenAuthorizationStatusAuthorized;
              break;
          case CNAuthorizationStatusNotDetermined:
              status = TenAuthorizationStatusNotDetermined;
              break;
          case CNAuthorizationStatusRestricted:
              status = TenAuthorizationStatusRestricted;
              break;
          default:
              status = TenAuthorizationStatusDenied;
              break;
        }
      } else {
        switch (ABAddressBookGetAuthorizationStatus()) {
          case kABAuthorizationStatusAuthorized:
            status = TenAuthorizationStatusAuthorized;
            break;
          case kABAuthorizationStatusNotDetermined:
            status = TenAuthorizationStatusNotDetermined;
            break;
          default:
            status = TenAuthorizationStatusDenied;
            break;
        }
      }
      return status;
    }
    

    8.2 权限请求

    if (@available(iOS 9.0, *)) {
      [[[CNContactStore alloc] init] requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
    
      }];
    }else {
      ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
      ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
    
      });
    }
    

    9 互联网权限

    引入头文件#import <CoreTelephony/CTCellularData.h>

    9.1 权限获取

    +(TenAuthorizationStatus)netStatus {
        TenAuthorizationStatus status;
        switch ([[CTCellularData alloc] init].restrictedState) {
            case kCTCellularDataNotRestricted:
                status = TenAuthorizationStatusAuthorized;
                break;
            case kCTCellularDataRestrictedStateUnknown:
                status = TenAuthorizationStatusNotDetermined;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    9.2 权限请求

    系统未提供接口供开发者手动请求网络权限,iOS10以上系统,应用首次请求网络会自动弹出,一个应用只弹出一次,卸载也不会重新弹出


    10 蓝牙权限

    引入头文件#import <CoreBluetooth/CoreBluetooth.h>

    10.1 权限获取

    +(TenAuthorizationStatus)bluetoothStatus {
        TenAuthorizationStatus status;
        switch ([CBPeripheralManager authorizationStatus]) {
            case CBPeripheralManagerAuthorizationStatusAuthorized:
                status = TenAuthorizationStatusAuthorized;
                break;
            case CBPeripheralManagerAuthorizationStatusNotDetermined:
                status = TenAuthorizationStatusNotDetermined;
                break;
            case CBPeripheralManagerAuthorizationStatusRestricted:
                status = TenAuthorizationStatusRestricted;
                break;
            default:
                status = TenAuthorizationStatusDenied;
                break;
        }
        return status;
    }
    

    10.2 权限请求

    蓝牙权限请求与定位权限相似,请求的结果是在代理中返回的,可以自己做一层封装,与其他系统权限请求一样用block的形式将结果返回。
    封装方法调用

    [[TenBluetoothManager shareManager] ten_requestBluetoothRequest:^(BOOL granted, CBPeripheralManagerAuthorizationStatus status) {
    
    }];
    

    TenBluetoothManager.h

    #import <Foundation/Foundation.h>
    #import <CoreBluetooth/CoreBluetooth.h>
    
    @interface TenBluetoothManager : NSObject
    /**单例方法*/
    +(instancetype)shareManager;
    /**
     唤起请求蓝牙权限
     @param block 结果回调
     */
    -(void)ten_requestBluetoothRequest:(void (^) (BOOL granted, CBPeripheralManagerAuthorizationStatus status))block;
    @end
    

    TenBluetoothManager.m

    #import "TenBluetoothManager.h"
    
    @interface TenBluetoothManager () <CBCentralManagerDelegate>
    /**蓝牙管理类*/
    @property (nonatomic, strong) CBCentralManager *cbCentralManager;
    /**请求蓝牙权限回调*/
    @property (nonatomic, copy) void (^bluetoothAuthBlock) (BOOL granted, CBPeripheralManagerAuthorizationStatus status);
    @end
    
    static TenBluetoothManager *_bluetoothManager;
    @implementation TenBluetoothManager
    
    #pragma mark - 构造
    /**构造方法*/
    +(instancetype)allocWithZone:(struct _NSZone *)zone {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            if (_bluetoothManager == nil) {
                _bluetoothManager = [super allocWithZone:zone];
            }
        });
        return _bluetoothManager;
    }
    
    /**单例方法*/
    +(instancetype)shareManager {
        return [[self alloc] init];
    }
    
    #pragma mark - public
    -(void)ten_requestBluetoothRequest:(void (^)(BOOL, CBPeripheralManagerAuthorizationStatus))block {
        self.bluetoothAuthBlock = block;
        [self.cbCentralManager scanForPeripheralsWithServices:nil options:nil];
    }
    
    #pragma mark - CBCentralManagerDelegate
    -(void)centralManagerDidUpdateState:(CBCentralManager *)central {
        if (self.bluetoothAuthBlock) {
            self.bluetoothAuthBlock(self.authStatus == CBPeripheralManagerAuthorizationStatusAuthorized, self.authStatus);
        }
    }
    
    #pragma mark - lazy
    -(CBCentralManager *)cbCentralManager {
        if (!_cbCentralManager) {
            _cbCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
        }
        return _cbCentralManager;
    }
    

    相关文章

      网友评论

        本文标题:【iOS开发笔记】系统权限的获取和请求

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