【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开发笔记】系统权限的获取和请求

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

  • iOS开发常用权限汇总

    主要总结下以下常用权限的获取及请求授权用法等(均不考虑iOS8以下系统):网络权限 推送权限 定位权限 通讯录权限...

  • 权限库升级了~

    关于权限相关的文章已经发了不少:iOS开发中的这些权限,你搞懂了吗?、如何获取iOS应用网络权限?、iOS开发中权...

  • [续]iOS开发中的这些权限,你搞懂了吗?

    前言 上篇文章iOS开发中的这些权限,你搞懂了吗?介绍了一些常用权限的获取和请求方法,知道这些方法的使用基本上可以...

  • iOS开发中权限再度梳理

    前言 上篇文章iOS开发中的这些权限,你搞懂了吗?介绍了一些常用权限的获取和请求方法,知道这些方法的使用基本上可以...

  • 01_iOS Jailbreak初识

    iOS越狱(iOS Jailbreak)概念 利用iOS系统的漏洞,获取iOS系统的最高权限(Root),解开之前...

  • 越狱环境搭建

    越狱简介 iOS越狱(iOS Jailbreak):利用iOS系统漏洞,获取iOS系统的最高(root)权限,解开...

  • iOS权限管理类

    PermissionManager 一个解决IOS权限库,只需传入权限类型,就可以 方便请求权限、获取权限状态。 ...

  • 逆向(1)-iOS越狱开发环境基本配置

    最近在开发iOS的自动化开发工具.需要hook消息通知和地理请求权限, 因为自动化脚本跑上去无法处理这种系统弹窗....

  • 获取用户授权,如:定位,通知,录音等。

    获取用户位置权限 iOS获取系统相关权限(iOS 7以上) 先来看看位置的一些权限: 这里就列出我用的定位的代码:...

网友评论

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

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