iOS开发中权限再度梳理
前言
上篇文章iOS开发中的这些权限,你搞懂了吗?介绍了一些常用权限的获取和请求方法,知道这些方法的使用基本上可以搞定大部分应用的权限访问的需求。但是,这些方法并不全面,不能涵盖住所有权限访问的方法。
So,笔者在介绍一下剩下的几种权限的访问方法和一些使用上的注意事项,希望能给大家的开发过程带来一丝便利。
最后,笔者将经常使用的权限请求方法封装开源库JLAuthorizationManager送给大家,欢迎大家pull request 和 star~~
权限
语音识别
媒体资料库/Apple Music
Siri
健康数据共享
蓝牙
住宅权限(HomeKit)
社交账号体系权限
活动与体能训练记录
广告标识
语音识别
引入头文件: @import Speech;
首先判断当前应用所处的权限状态,若当前状态为NotDetermined(未确定),此时,需要调用系统提供的请求权限方法,同时也是触发系统弹窗的所在点;
该权限涉及到的类为 SFSpeechRecognizer,具体代码如下:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
 | 
- (void)p_requestSpeechRecognizerAccessWithAuthorizedHandler:(void(^)())authorizedHandler                                         unAuthorizedHandler:(void(^)())unAuthorizedHandler{    SFSpeechRecognizerAuthorizationStatus authStatus = [SFSpeechRecognizer authorizationStatus];    if (authStatus == SFSpeechRecognizerAuthorizationStatusNotDetermined) {         //调用系统提供的权限访问的方法        [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {            if (status == SFSpeechRecognizerAuthorizationStatusAuthorized) {                dispatch_async(dispatch_get_main_queue(), ^{                     //授权成功后                    authorizedHandler ? authorizedHandler() : nil;                });            }else{                dispatch_async(dispatch_get_main_queue(), ^{                    //授权失败后                    unAuthorizedHandler ? unAuthorizedHandler() : nil;                });            }        }];    }else if (authStatus == SFSpeechRecognizerAuthorizationStatusAuthorized){        authorizedHandler ? authorizedHandler() : nil;    }else{        unAuthorizedHandler ? unAuthorizedHandler() : nil;    }} | 
需要注意的是,调用requestAuthorization方法的block回调是在任意的子线程中进行的,如果你需要在授权成功后刷新UI的话,需要将对应的方法置于主线程中进行,笔者将上述方法默认在主线程中进行。后续权限请求方法与此类似,不再赘述。
在info.plist添加指定的配置信息,如下所示:

Speech Recognizer
媒体资料库/Apple Music
导入头文件@import MediaPlayer;
使用类MPMediaLibrary进行权限访问,代码如下;
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
 | 
- (void)p_requestAppleMusicAccessWithAuthorizedHandler:(void(^)())authorizedHandler                                   unAuthorizedHandler:(void(^)())unAuthorizedHandler{    MPMediaLibraryAuthorizationStatus authStatus = [MPMediaLibrary authorizationStatus];    if (authStatus == MPMediaLibraryAuthorizationStatusNotDetermined) {        [MPMediaLibrary requestAuthorization:^(MPMediaLibraryAuthorizationStatus status) {            if (status == MPMediaLibraryAuthorizationStatusAuthorized) {                dispatch_async(dispatch_get_main_queue(), ^{                    authorizedHandler ? authorizedHandler() : nil;                });            }else{                dispatch_async(dispatch_get_main_queue(), ^{                    unAuthorizedHandler ? unAuthorizedHandler() : nil;                });            }        }];    }else if (authStatus == MPMediaLibraryAuthorizationStatusAuthorized){         authorizedHandler ? authorizedHandler() : nil;    }else{        unAuthorizedHandler ? unAuthorizedHandler() : nil;    }} | 
在info.plist添加指定的配置信息,如下所示:

Media
Siri
导入头文件@import Intents;;
与其他权限不同的时,使用Siri需要在Xcode中Capabilities打开Siri开关,Xcode会自动生成一个xx.entitlements文件,若没有打开该开关,项目运行时会报错。
实现代码如下:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
 | 
- (void)p_requestSiriAccessWithAuthorizedHandler:(void(^)())authorizedHandler                             unAuthorizedHandler:(void(^)())unAuthorizedHandler{    INSiriAuthorizationStatus authStatus = [INPreferences siriAuthorizationStatus];    if (authStatus == INSiriAuthorizationStatusNotDetermined) {        [INPreferences requestSiriAuthorization:^(INSiriAuthorizationStatus status) {            if (status == INSiriAuthorizationStatusAuthorized) {                dispatch_async(dispatch_get_main_queue(), ^{                     authorizedHandler ? authorizedHandler() : nil;                });            }else{                dispatch_async(dispatch_get_main_queue(), ^{                    unAuthorizedHandler ? unAuthorizedHandler() : nil;                });            }        }];    }else if (authStatus == INSiriAuthorizationStatusAuthorized){        authorizedHandler ? authorizedHandler() : nil;    }else{        unAuthorizedHandler ? unAuthorizedHandler() : nil;    }} | 
健康数据共享
导入头文件@import HealthKit;
健康数据共享权限相对其他权限相对复杂一些,分为写入和读出权限.
在Xcode 8中的info.plist需要设置以下两种权限:
| 
 1 
2 
 | 
1、Privacy - Health Update Usage Description2、Privacy - Health Share Usage Description | 
具体实现代码:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
 | 
//设置写入/共享的健康数据类型- (NSSet *)typesToWrite {    HKQuantityType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];    HKQuantityType *distanceType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];    return [NSSet setWithObjects:stepType,distanceType, nil];}//设置读写以下为设置的权限类型:- (NSSet *)typesToRead {   HKQuantityType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];    HKQuantityType *distanceType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];    return [NSSet setWithObjects:stepType,distanceType, nil];}//需要确定设备支持HealthKitif ([HKHealthStore isHealthDataAvailable]) {        return;    }HKHealthStore *healthStore = [[HKHealthStore alloc] init];    NSSet * typesToShare = [self typesToWrite];    NSSet * typesToRead = [self typesToRead];    [healthStore requestAuthorizationToShareTypes:typesToShare readTypes:typesToRead completion:^(BOOL success, NSError * _Nullable error) {        if (success) {            dispatch_async(dispatch_get_main_queue(), ^{                NSLog(@"Health has authorized!");            });        }else{            dispatch_async(dispatch_get_main_queue(), ^{                NSLog(@"Health has not authorized!");            });        }    }]; | 
蓝牙
需要导入头文件@import CoreBluetooth;
蓝牙的权限检测相对其他会复杂一些,需要在代理中检测蓝牙状态;
获取蓝牙权限:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
 | 
- (void)checkBluetoothAccess {    CBCentralManager *cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];    CBManagerState state = [cbManager state];    if(state == CBManagerStateUnknown) {        NSLog(@"Unknown!");    }    else if(state == CBManagerStateUnauthorized) {         NSLog(@"Unauthorized!");    }    else {        NSLog(@"Granted!");    }}- (void)centralManagerDidUpdateState:(CBCentralManager *)central {//这个代理方法会在蓝牙权限状态发生变化时被调用,并且可以根据不同的状态进行相应的修改UI或者数据访问的操作。} | 
请求蓝牙权限
| 
 1 
2 
3 
4 
5 
 | 
- (void)requestBluetoothAccess {    CBCentralManager *cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];//该方法会显示用户同意的弹窗    [cbManager scanForPeripheralsWithServices:nil options:nil];} | 
住宅权限(HomeKit)
需导入头文件@import HomeKit;
HomeKit请求权限的方法如下:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
 | 
- (void)requestHomeAccess {    self.homeManager = [[HMHomeManager alloc] init];//当设置该代理方法后,会请求用户权限    self.homeManager.delegate = self;}- (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager {    if (manager.homes.count > 0) {        // home的数量不为空,即表示用户权限已通过    }    else {        __weak HMHomeManager *weakHomeManager = manager; // Prevent memory leak        [manager addHomeWithName:@"Test Home" completionHandler:^(HMHome *home, NSError *error) {            if (!error) {               //权限允许            }            else {                if (error.code == HMErrorCodeHomeAccessNotAuthorized) {                   //权限不允许                }                else {                    //处理请求产生的错误                }            }            if (home) {                [weakHomeManager removeHome:home completionHandler:^(NSError * _Nullable error) {                    //移除Home                }];            }        }];    }} | 
社交账号体系权限
导入头文件@import Accounts;
获取对应的权限:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
 | 
- (void)checkSocialAccountAuthorizationStatus:(NSString *)accountTypeIndentifier {    ACAccountStore *accountStore = [[ACAccountStore alloc] init];    ACAccountType *socialAccount = [accountStore accountTypeWithAccountTypeIdentifier:accountTypeIndentifier];    if ([socialAccount accessGranted]) {        NSLog(@"权限通过了");    }else{         NSLog(@"权限未通过!"); }} | 
accountTypeIndentifier 可以是以下类型:
| 
 1 
2 
3 
4 
5 
 | 
ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierTwitter NS_AVAILABLE(NA, 5_0);ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierFacebook NS_AVAILABLE(NA, 6_0);ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierSinaWeibo NS_AVAILABLE(NA, 6_0);ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierTencentWeibo NS_AVAILABLE(NA, 7_0);ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierLinkedIn NS_AVAILABLE(NA, NA); | 
请求对应的权限:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
 | 
- (void)requestTwitterAccess {    ACAccountStore *accountStore = [[ACAccountStore alloc] init];    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:accountTypeIdentifier];         [accountStore requestAccessToAccountsWithType: accountType options:nil completion:^(BOOL granted, NSError *error) {        dispatch_async(dispatch_get_main_queue(), ^{           if(granted){                 NSLog(@"授权通过了");            }else{                 NSLog(@"授权未通过");            }        });    }];} | 
活动与体能训练记录
导入头文件@import CoreMotion;
具体实现代码:
| 
 1 
2 
3 
4 
5 
6 
7 
 | 
//访问活动与体能训练记录    CMMotionActivityManager *cmManager = [[CMMotionActivityManager alloc] init];    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    [cmManager startActivityUpdatesToQueue:queue withHandler:^(CMMotionActivity *activity) {             //授权成功后,会进入Block方法内,授权失败不会进入Block方法内    }]; | 
广告标识
导入头文件@import AdSupport;
获取广告标识的权限状态:
| 
 1 
 | 
BOOL isAuthorizedForAd = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]; | 
在使用advertisingIdentifier属性前,必须调用上述方法判断是否支持,如果上述方法返回值为NO,则advertising ID访问将会受限。
小结一下
通过以上两篇文章的整理,有关iOS系统权限问题的处理基本上涵盖完全了;
并不是所有的权限访问都有显式的调用方法,有些是在使用过程中进行访问的,比如定位权限、蓝牙共享权限、Homekit权限、活动与体能训练权限,这些权限在使用时注意回调方法中的权限处理;
HomeKit、HealthKit、Siri需要开启Capabilities中的开关,即生成projectName.entitlements文件;
开源库JLAuthorizationManager支持集成大部分常用的权限访问,便捷使用 welcome to pull request or star
iOS开发中权限再度梳理的更多相关文章
- 再续iOS开发中的这些权限
		
前言 上篇文章iOS开发中的这些权限,你搞懂了吗?介绍了一些常用权限的获取和请求方法,知道这些方法的使用基本上可以搞定大部分应用的权限访问的需求.但是,这些方法并不全面,不能涵盖住所有权限访问的方法. ...
 - ios开发中的小技巧
		
在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...
 - fir.im Weekly - iOS开发中的Git流程
		
本期 fir.im Weekly 收集了微博上的热转资源,包含 Android.iOS 开发工具.源码等好用的轮子,还有一些 APP 设计的 Tips,希望对你有用. 精仿知乎日报 iOS 端 @我偏 ...
 - 在iOS开发中使用FMDB
		
在iOS开发中使用FMDB 前言 SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库.iOS SDK 很早就支持了 SQLite,在使用时,只需 ...
 - 【转】在iOS开发中使用FMDB
		
本文转载自:唐巧的博客 在iOS开发中使用FMDB APR 22ND, 2012 前言 SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库.iO ...
 - 总结iOS开发中的断点续传那些事儿
		
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
 - iOS开发中静态库之".framework静态库"的制作及使用篇
		
iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...
 - iOS开发中静态库制作 之.a静态库制作及使用篇
		
iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...
 - IOS 开发中  Whose view is not in the window hierarchy  错误的解决办法
		
在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...
 
随机推荐
- NOIP2011 day2 第一题 计算系数
			
计算系数 NOIP2011 day2 第一题 描述 给定一个多项式(ax+by)^k,请求出多项式展开后x^n*y^m项的系数. 输入格式 共一行,包含5 个整数,分别为 a ,b ,k ,n ,m, ...
 - QlikSense系列(3)——QlikSense建立数据模型
			
QlikSense管理数据在帮助中写的比较清楚 https://help.qlik.com/zh-CN/sense/3.1/Subsystems/Hub/Content/LoadData/load-d ...
 - king枚举帮助类
			
可以方便的实现枚举 枚举 public enum DeptType { [Description("科室1")] Professional = , [Description(&qu ...
 - json属性(Jackson)
			
Jackson相关:使用Jackson相关的注解时一定要注意自己定义的属性命名是否规范. 命名不规范时会失去效果.(例如Ename ,Eage 为不规范命名.“nameE”,“ageE”为规范命名). ...
 - ndk编译curl以及使用
			
百度搜ndk curl,大多都是转发的同一篇文章,文章中提供的lcur_config.h,不一定适合你的curl版本. 后来找到http://download.csdn.net/download/cs ...
 - PCL:解决PCL和OpenCV冲突的方法
			
不是PCL的问题,而是OpenCV的问题. (1):先包含PCL库,再包含OpenCV库: (2):把里面的UCHAR冲突全部换掉! 如果你有闲情逸致,用正则表达式 慢慢替换去吧! (3):或者把F ...
 - phpstudy不显示目录列表---设置方法
			
打开phpstudy,显示的项目文件路径不见了,其实是phpstudy的设置问题.以下是设置方法. 并将一下几个文件删除即可
 - 优动漫PAINT用户界面介绍
			
使用优动漫PAINT能够快速实现工程巨大的漫画.插画以及动画,从13年发布至今一直备受好评,目前优动漫PAINT1.6.6.1是最新的版本,新版本的完善也受到更多年轻伙伴的青睐,使用优动漫PAINT可 ...
 - Select, Poll,Epoll
			
Date: 2019-06-19 Author: Sun 1. Select  select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当se ...
 - JS 封装一个求n~m的求和函数
			
var a = 0; cc(2,10); function cc(n,m){ for(var i =n;i<(m+1);i++){ a = a + ...