权限小结

作者: 奚山遇白 | 来源:发表于2019-11-26 20:02 被阅读0次

    最近工作需要做了权限相关的部分数据整理,mark下~

    1.plist配置

    我们都知道想要实现对应权限访问提示,需要在项目的plist文件中提前配置,常用的配置如下所示:

    key 描述
    Privacy - Media Library Usage Description 媒体资料库
    NSBluetoothAlwaysUsageDescription 蓝牙
    Privacy - Bluetooth Peripheral Usage Description 蓝牙外围设备
    Privacy - Calendars Usage Description 日历
    Privacy - Camera Usage Description 相机
    Privacy - Contacts Usage Description 通讯录
    Privacy - Location Always Usage Description 始终使用位置信息
    Privacy - Location When In Use Usage Description 应用使用过程中允许使用位置信息
    Privacy - Microphone Usage Description 麦克风
    Privacy - Motion Usage Description 运动与健身
    Privacy - Photo Library Additions Usage Description 相册写
    Privacy - Photo Library Usage Description 相册读
    Privacy - Reminders Usage Description 提醒事项
    Privacy - Siri Usage Description Siri

    2.权限请求

    下面我们来介绍一下各个权限状态控制的代码:

    2.1 相机

    首先需要 #import <AVFoundation/AVFoundation.h>

    获取状态:

    typedef NS_ENUM(NSInteger, AVAuthorizationStatus) {
        AVAuthorizationStatusNotDetermined = 0, // 用户还未选择
        AVAuthorizationStatusRestricted    = 1, // 权限受限,例如开启家长控制
        AVAuthorizationStatusDenied        = 2, // 用户拒绝授权
        AVAuthorizationStatusAuthorized    = 3, // 用户允许授权
    }
    
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    

    请求允许:

    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            NSLog(@"%@",granted ? @"开启相机设置":@"关闭相机设置");
        }];
    

    2.2 麦克风

    首先需要 #import <AVFoundation/AVFoundation.h>

    获取状态:

    // 状态枚举同2.1相机,此处不再赘述
    
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    

    请求允许:

    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            NSLog(@"%@",granted ? @"开启相机设置":@"关闭相机设置");
        }];
    

    2.3 相册

    首先需要 #import <Photos/Photos.h>

    获取状态:

    typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
        PHAuthorizationStatusNotDetermined = 0, // 用户还未选择
        PHAuthorizationStatusRestricted,        // 权限受限,例如开启家长控制
        PHAuthorizationStatusDenied,            // 用户拒绝授权
        PHAuthorizationStatusAuthorized         // 用户允许授权
    }
    
    PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
    

    请求允许:

    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (status == PHAuthorizationStatusAuthorized) {
                    NSLog(@"开启相册设置");
                }else {
                    NSLog(@"关闭相册设置");
                }
            });
        }];
    

    2.4 日历

    首先需要 #import <EventKit/EventKit.h>

    获取状态:

    typedef NS_ENUM(NSInteger, EKAuthorizationStatus) {
        EKAuthorizationStatusNotDetermined = 0, // 用户还未选择
        EKAuthorizationStatusRestricted, // 权限受限,例如开启家长控制
        EKAuthorizationStatusDenied, // 用户拒绝授权
        EKAuthorizationStatusAuthorized, // 用户允许授权
    }
    
    EKAuthorizationStatus authStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
    

    请求允许:

    EKEventStore *eventStore = [[EKEventStore alloc] init];
    [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"%@",error ? @"日历授权失败":@"日历授权成功");
        });
    }];
    

    2.5 备忘录

    首先需要 #import <EventKit/EventKit.h>

    获取状态:

    // 状态枚举同2.4日历,此处不再赘述
    
    EKAuthorizationStatus authStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder];
    

    请求允许:

    EKEventStore *eventStore = [[EKEventStore alloc] init];
    [eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError * _Nullable error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"%@",error ? @"提醒事项授权失败":@"提醒事项授权成功");
            });
        }];
    

    2.6 通讯录

    首先需要 #import <Contacts/Contacts.h>

    获取状态:

    typedef NS_ENUM(NSInteger, CNAuthorizationStatus)
    {
        CNAuthorizationStatusNotDetermined = 0, // 用户还未选择
        CNAuthorizationStatusRestricted, // 权限受限,例如开启家长控制
        CNAuthorizationStatusDenied, // 用户拒绝授权
        CNAuthorizationStatusAuthorized // 用户允许授权
    }
    
    CNAuthorizationStatus authStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
    

    请求允许:

    CNContactStore *store = [[CNContactStore alloc] init];
    [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError*  _Nullable error) {
        NSLog(@"%@",error ? @"通讯录授权失败":@"通讯录授权成功");
    }];
    

    2.7 运动与健身

    首先需要 #import <CoreMotion/CoreMotion.h>【需注意该权限仅在iOS 11之后才开始支持】

    获取状态:

    typedef NS_ENUM(NSInteger, CMAuthorizationStatus) {
        CMAuthorizationStatusNotDetermined = 0, // 用户还未选择
        CMAuthorizationStatusRestricted, // 权限受限,例如开启家长控制
        CMAuthorizationStatusDenied, // 用户拒绝授权
        CMAuthorizationStatusAuthorized // 用户允许授权
    }
    
    CMAuthorizationStatus authStatus = [CMMotionActivityManager authorizationStatus];
    

    请求允许:

    // 可以通过访问实际数据唤起权限弹框
    // 需注意,需要首先#import <CoreMotion/CMPedometer.h>
    
    if ([CMPedometer isStepCountingAvailable]) {
        CMPedometer *per = [[CMPedometer alloc]init];
        [per queryPedometerDataFromDate:[NSDate dateWithTimeIntervalSinceNow:-60*60*24*2] toDate:[NSDate dateWithTimeIntervalSinceNow:-60*60*24*1] withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) {
            if (error) {
                NSLog(@"error====%@",error);
            }else {
                NSLog(@"步数====%@",pedometerData.numberOfSteps);
                NSLog(@"距离====%@",pedometerData.distance);
            }
        }];
    }else{
        NSLog(@"记步功能不可用");
    }
    

    2.8 通知

    获取状态:

    typedef NS_OPTIONS(NSUInteger, UIUserNotificationType) {
        UIUserNotificationTypeNone    = 0,      // 均不使用
        UIUserNotificationTypeBadge   = 1 << 0, // 应用角标通知
        UIUserNotificationTypeSound   = 1 << 1, // 应用响铃通知
        UIUserNotificationTypeAlert   = 1 << 2, // 应用弹框通知
    }
    
    UIUserNotificationSettings *setting = [[UIApplication sharedApplication] currentUserNotificationSettings];
    if (setting.types == UIUserNotificationTypeNone) {
        // 通知未开启
    }else{
        // 开启了某一/多个通知设置
    }
    
    
    // 在application:didRegisterUserNotificationSettings:方法中也可获取通知设置状态
    

    2.9 位置

    首先需要 #import <CoreLocation/CoreLocation.h>

    获取状态:

    typedef NS_ENUM(int, CLAuthorizationStatus) {
        kCLAuthorizationStatusNotDetermined = 0, // 用户还未选择
        kCLAuthorizationStatusRestricted, // 权限受限,例如开启家长控制
        kCLAuthorizationStatusDenied, // 用户拒绝授权
        kCLAuthorizationStatusAuthorizedAlways API_AVAILABLE(macos(10.12), ios(8.0)), //始终允许访问
        kCLAuthorizationStatusAuthorizedWhenInUse API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos), // 应用使用过程中允许
    }
    
    CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus];
    

    请求允许:

    // 与2.7类似可以通过访问实际数据唤起权限弹框
    [self.locationManager startUpdatingLocation];
    
    
    - (CLLocationManager *)locationManager {
        if (!_locationManager) {
            // 定位管理
            _locationManager = [[CLLocationManager alloc] init];// 初始化
            
            if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]){
                [_locationManager performSelector:@selector(requestWhenInUseAuthorization)];
            }
            
            [_locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];// 设置精度值
            [_locationManager setDelegate:self];
        }
        return _locationManager;
    }
    

    2.10 siri

    首先需要 #import <Intents/Intents.h>【需注意该权限仅在iOS 10之后才开始支持】

    获取状态:

    typedef NS_ENUM(NSInteger, INSiriAuthorizationStatus) {
        INSiriAuthorizationStatusNotDetermined = 0, // 用户还未选择
        INSiriAuthorizationStatusRestricted, // 权限受限
        INSiriAuthorizationStatusDenied, // 用户拒绝授权
        INSiriAuthorizationStatusAuthorized // 用户允许授权
    }
    
    // 经实际测试,下列代码获取到的siri权限状态仅为首次弹框时用户的选择相关,后续在设置页面更改对应多个配置项例如:搜索与建议/显示应用等开关的状态无关。笔者做了个测试是初始弹框选择不允许,然后自己写了个捷径,然后打开设置页面的搜索与建议,通过下列代码获取到的状态还是**拒绝**,但是捷径是可用的,但是相反的初始弹框选择允许,关闭设置页面的搜索与建议,通过下列代码获取到的状态还是**允许**,但是捷径是不可用的。另外由于官方并无其他API,所以笔者暂时猜测下列代码获取到的状态项是独立于设置中多项开关的,如果有读者彻底弄清楚了其原理机制欢迎给我留言
    INSiriAuthorizationStatus authStatus = [INPreferences siriAuthorizationStatus];
    

    2.11 蓝牙

    首先需要 #import <CoreBluetooth/CoreBluetooth.h>【需注意该权限虽然很早就支持,但是设置页面对应的开关仅在iOS 13之后才开始支持,iOS 13之前在设置页面是没有该对应开关的】

    另外蓝牙比较不同的是,它是一种双向性的权限,即你本身的设备可以作为中心设备,也可以作为被扫描到的外围设备,所以官方提供了CBCentralManager和CBPeripheralManager分别来管理中心和外围设备的情况。

    作为中心设备获取状态:

    typedef NS_ENUM(NSInteger, CBManagerState) {
        CBManagerStateUnknown = 0, //未知,用户未选择
        CBManagerStateResetting,
        CBManagerStateUnsupported, //不支持
        CBManagerStateUnauthorized, //未授权
        CBManagerStatePoweredOff, //关闭
        CBManagerStatePoweredOn, //开启
    }
    
    // 作为中心设备,苹果并未给我们开辟直接获取状态的API,我们需要创建对应的实例才能获取
    if (self.cbManager.state == CBManagerStatePoweredOn) {
        // 蓝牙开关开启
    }else{
        // 蓝牙开关关闭
    }
    
    // 另外实测上述代码并不能获取实时状态,所以需要结合下列代理一起使用
    - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
        if (central.state == CBManagerStatePoweredOn) {
            // 蓝牙开关开启
        }else{
            // 蓝牙开关关闭
        }
        // 可以使用通知实现逻辑更新
        [[NSNotificationCenter defaultCenter] postNotificationName:WYPermitSDKBluetoothStateChanged object:nil];
    }
    
    - (CBCentralManager *)cbManager {
        if (!_cbManager) {
            _cbManager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
        }
        return _cbManager;
    }
    
    

    作为外围设备获取状态:

    typedef NS_ENUM(NSInteger, CBPeripheralManagerAuthorizationStatus) {
        CBPeripheralManagerAuthorizationStatusNotDetermined = 0, // 用户未配置
        CBPeripheralManagerAuthorizationStatusRestricted, // 不支持
        CBPeripheralManagerAuthorizationStatusDenied, // 用户关闭
        CBPeripheralManagerAuthorizationStatusAuthorized, // 用户开启   
    } 
    
    CBPeripheralManagerAuthorizationStatus authStatus =  [CBPeripheralManager authorizationStatus];
    

    读到一篇文章关于蓝牙写的很详细,大家可以参考下:推荐的文章-iOS蓝牙知识快速入门(详尽版)

    3.跳转到应用设置页面

    if (@available(iOS 10.0, *)) {
        // iOS10之后可以直接跳转到应用内设置页面
        NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
        [[UIApplication sharedApplication] openURL:url];
    }else {
        NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"prefs:root=%@",[[NSBundle mainBundle] bundleIdentifier]]];
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            [[UIApplication sharedApplication] openURL:url];
        }
    }
    

    相关文章

      网友评论

        本文标题:权限小结

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