前言

上篇文章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 Description
2、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];
}
 
//需要确定设备支持HealthKit
if ([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开发中权限再度梳理的更多相关文章

  1. 再续iOS开发中的这些权限

    前言 上篇文章iOS开发中的这些权限,你搞懂了吗?介绍了一些常用权限的获取和请求方法,知道这些方法的使用基本上可以搞定大部分应用的权限访问的需求.但是,这些方法并不全面,不能涵盖住所有权限访问的方法. ...

  2. ios开发中的小技巧

    在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...

  3. fir.im Weekly - iOS开发中的Git流程

    本期 fir.im Weekly 收集了微博上的热转资源,包含 Android.iOS 开发工具.源码等好用的轮子,还有一些 APP 设计的 Tips,希望对你有用. 精仿知乎日报 iOS 端 @我偏 ...

  4. 在iOS开发中使用FMDB

    在iOS开发中使用FMDB 前言 SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库.iOS SDK 很早就支持了 SQLite,在使用时,只需 ...

  5. 【转】在iOS开发中使用FMDB

    本文转载自:唐巧的博客 在iOS开发中使用FMDB APR 22ND, 2012 前言 SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库.iO ...

  6. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  7. iOS开发中静态库之".framework静态库"的制作及使用篇

    iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...

  8. iOS开发中静态库制作 之.a静态库制作及使用篇

    iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...

  9. IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法

    在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...

随机推荐

  1. colab使用谷歌云中的文件

    colab使用谷歌云中文件 无法一劳永逸 Google Colab最大的不足就是使用虚拟机,这意味着我们自行安装的库虚拟机重启之后,就会被复原,比如keras,数据无法持久化.为了能够持久保存数据,我 ...

  2. 动画和图形:OpenGL ES

    在网络层,互联网提供所有应用程序都要使用的两种类型的服务,尽管目前理解这些服务的细节并不重要,但在所有TCP/IP概述中,都不能忽略他们: 无连接分组交付服务(Connectionless Packe ...

  3. WebForm--j简单控件、简单的登录(怎么链接数据库)

    一.简单控件 1.label:边框(边框的颜色.样式.粗细)  是专门显示文字的,   被编译后是    <span id="Label1">Label</spa ...

  4. 揭秘IPHONE X刷脸认证的技术奥秘

    苹果最新发布的Iphone X具有一个全新的功能叫做刷脸认证,背后的技术其实是生物密码的更新,通过人脸识别取代了传统的指纹识别,大家肯定对这种新技术非常感兴趣,下面我们通过这篇文章为大家介绍人脸识别的 ...

  5. 【Oracle】审计

    1.审计的功能:监控用户在database 的 action (操作) 2.审计分类: 1) session :在同一个session,相同的语句只产生一个审计结果(默认) 2) access : 在 ...

  6. fabric.js 翻转,复制粘贴,隐藏, 删除,历史记录,撤销, 剪切, 图层,组合打散,锁定等功能

    用vue写的 显示,隐藏 hide(){ this.canvas.getActiveObject().set('opacity', 0).setCoords(); this.canvas.reques ...

  7. Jenkins介绍-安装-部署...

    1.背景      大师Martin Fowler对持续集成是这样定义的:持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成. ...

  8. 避免关注底层硬件,Nvidia将机器学习与GPU绑定

    Nvidia释放的一组cuDNN的库,有效的实现了其与多种深度学习框架的整合.基于cuDNN,加速了代码的运行,同时让研究员避免去关心底层硬件性能. 关键字: 编程语言语音识别Nvidia 原文链接: ...

  9. 互联网的大数据神话——NoSQL

    本文摘抄于:<纵横大数据--云计算数据基础设施> 何小朝著 Chapter5. NewSQL--关系数据库联邦/联合 5.4.2  互联网的神话 对强一致性的要求放松,是因为 互联网的分布 ...

  10. 使用PCL::GPU::遇到问题

    一:使用GPU进行点云分割,理论上可以极大地加快分割速度: 于是对PCL1.7.1进行了编译,回到32位系统,重设QT,编译成功(时间好漫长,一定要配置仔细,否则编译一次又一次浪费更多时间): 使用时 ...