iOS 系统权限检测功能

自从iOS8增加了权限需要征得用户同意后,后续iOS对权限的要求越来严格,记录一下各种权限的获取方法

1、定位权限(info.plist需要添加LocationWhenInUseUsageDescription + LocationAlwaysUsageDescription)

需要获取用户此时此刻的位置信息的时候需要使用到定位权限。
使用到了#import <CoreLocation/CoreLocation.h> // 定位框架
权限状态获取方法是:

CLAuthorizationStatus locationstats = [CLLocationManager authorizationStatus];

获取到的状态有:

typedef NS_ENUM(int, CLAuthorizationStatus) {
    kCLAuthorizationStatusNotDetermined = 0, // 还未请求过权限,一般是APP首次安装,然后第一次请求权限的时候才会出现这个状态,然后需要主动触发权限请求
    kCLAuthorizationStatusRestricted, // 拒绝状态
    kCLAuthorizationStatusDenied,//  用户已允许状态
    kCLAuthorizationStatusAuthorizedAlways NS_ENUM_AVAILABLE(10_12, 8_0),// “始终”定位
    kCLAuthorizationStatusAuthorizedWhenInUse NS_ENUM_AVAILABLE(NA, 8_0),// “使用应用期间”定位
    kCLAuthorizationStatusAuthorized NS_ENUM_DEPRECATED(10_6, NA, 2_0, 8_0, "Use kCLAuthorizationStatusAuthorizedAlways") // 此枚举已经废弃,使用kCLAuthorizationStatusAuthorizedAlways替代
};

当系统API返回的状态是kCLAuthorizationStatusNotDetermined还未授权过的状态的时候,我们需要主动发起授权请求,如果定位仅仅是“在APP使用期间”才涉及到定位需求的话,那么使用requestWhenInUseAuthorization方法请求权限,如果是无论什么时候都需要定位权限的话,那么使用requestAlwaysAuthorization方法请求权限,请求方法如下:

    CLLocationManager * locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    // 在app打开期间使用定位权限
    [locationManager requestWhenInUseAuthorization];
    // app在后台也可以持续定位
    [locationManager requestAlwaysAuthorization];

请求方法二选一。接着在CLLocationManagerDelegate代理里面实现

// 当此应用程序的授权状态更改时调用
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
}

方法,返回的status就是当前用的选择的状态了。需要注意的是,如果CLLocationManager对象被释放了,那么弹窗也会消失,所以可以把CLLocationManager对象变成属性或者成员变量。

2、消息通知

推送通知需要使用的框架是#import <UserNotifications/UserNotifications.h> // 通知框架
权限状态获取方法是:
此时要区分系统版本获取,在iOS10之后使用:

[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
    // 获取状态
    UNAuthorizationStatus authorizationStatus = settings.authorizationStatus;
}];

获取到的状态有:

// 该枚举在iOS 10 之后才能使用
typedef NS_ENUM(NSInteger, UNAuthorizationStatus) {
    UNAuthorizationStatusNotDetermined = 0, // 还未授权
    UNAuthorizationStatusDenied, // 被拒绝
    UNAuthorizationStatusAuthorized // 用户允许
} __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0);

请求权限通知的API方法:

// User authorization is required for applications to notify the user using UNUserNotificationCenter via both local and remote notifications.
- (void)requestAuthorizationWithOptions:(UNAuthorizationOptions)options completionHandler:(void (^)(BOOL granted, NSError *__nullable error))completionHandler;

// 使用方法
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
    //  granted 代表允许与否    
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程
    });                       
}];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码
UNAuthorizationOptions枚举是:

typedef NS_OPTIONS(NSUInteger, UNAuthorizationOptions) {
    UNAuthorizationOptionBadge   = (1 << 0),  // 角标
    UNAuthorizationOptionSound   = (1 << 1), // 声音
    UNAuthorizationOptionAlert   = (1 << 2), // 弹窗
    UNAuthorizationOptionCarPlay = (1 << 3),  // 车载
} __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0);

在iOS10之前使用

BOOL result = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
// result 就是授权状态 ...

3、录音权限(info.plist需要添加MicrophoneUsageDescription)

录音权限就要使用#import <AVFoundation/AVFoundation.h> // 音视频框架
请求录音权限通知的API方法:

    AVAudioSession * audioSession = [AVAudioSession sharedInstance];
    [audioSession requestRecordPermission:^(BOOL granted) {
        //  granted 代表允许与否  
        dispatch_async(dispatch_get_main_queue(), ^{
            //  回到主线程
        });
    }];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

4、相机权限(info.plist需要添加CameraUsageDescription)

相机权限就要使用#import <AVFoundation/AVFoundation.h> // 音视频框架
获取当前权限状态API:

AVAuthorizationStatus cameraAuthorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

获取到的状态有:

typedef NS_ENUM(NSInteger, AVAuthorizationStatus) {
    AVAuthorizationStatusNotDetermined = 0, // 未授权,需要调用方法触发授权
    AVAuthorizationStatusRestricted    = 1, // 已被限制,例如家长控制等等
    AVAuthorizationStatusDenied        = 2, //  已被拒绝
    AVAuthorizationStatusAuthorized    = 3, // 已允许
} NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

请求相机权限通知的API方法:

[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
    // granted 代表允许与否  
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程
    });
 }];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

5、相册权限(info.plist需要添加NSPhotoLibraryUsageDescription)

需要查看手机相册需要使用 iOS8.0之前使用#import <AssetsLibrary/AssetsLibrary.h> 和 iOS8.0之后使用 #import <Photos/Photos.h>
获取当前相册权限状态API,在iOS8.0之后使用:

PHAuthorizationStatus PHAssetsAuthorizationStatus = [PHPhotoLibrary authorizationStatus];

获取到的状态有:

typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
    PHAuthorizationStatusNotDetermined = 0,  // 还未授权,需要触发授权方法
    PHAuthorizationStatusRestricted,  // 已被限制,例如家长控制等等
    PHAuthorizationStatusDenied,   // 已被拒绝
    PHAuthorizationStatusAuthorized  // 已允许
} PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0);

请求相册权限通知的API方法:

[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程操作
    });
}];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

iOS 8.0之前使用API:

ALAuthorizationStatus ALAssetsAuthorizationStatus = [ALAssetsLibrary authorizationStatus];

获取到的状态有:

typedef NS_ENUM(NSInteger, ALAuthorizationStatus) {
    ALAuthorizationStatusNotDetermined ,  // 还未授权,需要触发授权方法
    ALAuthorizationStatusRestricted ,  // 已被限制,例如家长控制等等
    ALAuthorizationStatusDenied ,  // 已被拒绝
    ALAuthorizationStatusAuthorized // 已允许 
} NS_DEPRECATED_IOS(6_0, 9_0, "Use PHAuthorizationStatus in the Photos framework instead");

当获取到的状态是ALAuthorizationStatusNotDetermined需要触发授权方法,授权API是:

[ALAssetsLibrary alloc] init] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程
    });
} failureBlock:^(NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程
    });
}];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

6、通讯录权限(info.plist需要添加ContactsUsageDescription)

需要查看通讯录权限需要使用 iOS9.0之前使用#import <AddressBook/AddressBook.h> 和 iOS9.0之后使用 #import <Contacts/Contacts.h>
获取通讯录权限状态API,在iOS9.0之后使用:

CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];

获取到的状态有:

typedef NS_ENUM(NSInteger, CNAuthorizationStatus) {
    CNAuthorizationStatusNotDetermined = 0,  // 还未授权,需要触发授权方法
    CNAuthorizationStatusRestricted, // 已被限制,例如家长控制等等
    CNAuthorizationStatusDenied, // 已被拒绝
    CNAuthorizationStatusAuthorized // 已允许 
} NS_ENUM_AVAILABLE(10_11, 9_0);

当获取到的状态是CNAuthorizationStatusNotDetermined需要触发授权方法,授权API是:

[[[CNContactStore alloc] init] requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程操作
    });
 }];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

iOS 9.0之前使用API:

ABAuthorizationStatus authorizationStatus = ABAddressBookGetAuthorizationStatus();

获取到的状态有:

typedef CF_ENUM(CFIndex, ABAuthorizationStatus) {
    kABAuthorizationStatusNotDetermined = 0,  // 还未授权,需要触发授权方法
    kABAuthorizationStatusRestricted, // 已被限制,例如家长控制等等 
    kABAuthorizationStatusDenied, // 已被拒绝            
    kABAuthorizationStatusAuthorized // 已允许            
} AB_DEPRECATED("use CNAuthorizationStatus");

当获取到的状态是kABAuthorizationStatusNotDetermined时,需要触发授权方法,授权API是:

ABAddressBookRef bookref = ABAddressBookCreateWithOptions(NULL, NULL);
ABAddressBookRequestAccessWithCompletion(bookref, ^(bool granted, CFErrorRef error) {
    //  这里granted是用户点击后的状态
});

7、日历权限 + 日历提醒事件权限 (info.plist需要添加CalendarsUsageDescription + RemindersUsageDescription)

需要查看日历权限需要使用 #import <EventKit/EventKit.h>
获取当前权限状态API是:

// 获取日历权限
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
// 获取提醒事件权限
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder];

获取到的状态有:

typedef NS_ENUM(NSInteger, EKAuthorizationStatus) {
    EKAuthorizationStatusNotDetermined = 0,  // 还未授权,需要触发授权方法
    EKAuthorizationStatusRestricted, // 已被限制,例如家长控制等等 
    EKAuthorizationStatusDenied, // 已被拒绝    
    EKAuthorizationStatusAuthorized, // 已允许      
} NS_AVAILABLE(10_9, 6_0);

当获取到的状态是EKAuthorizationStatusNotDetermined时,需要触发授权方法,授权API是:

// 触发日历权限API
[[[EKEventStore alloc] init] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 需要回到主线程操作
    });
}];
// 触发提醒事件权限API
[[[EKEventStore alloc] init] requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError * _Nullable error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 需要回到主线程操作
    });
}];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

8、语音识别功能权限 (info.plist需要添加SpeechRecognitionUsageDescription)

语音识别功能api接口只有在iOS10之后才有,所以最低都要从iOS10开始使用
需要使用语音识别功能需要使用 #import <Speech/Speech.h>
获取当前权限状态API是:

SFSpeechRecognizerAuthorizationStatus status = [SFSpeechRecognizer authorizationStatus];

获取到的状态有:

typedef NS_ENUM(NSInteger, SFSpeechRecognizerAuthorizationStatus) {
    SFSpeechRecognizerAuthorizationStatusNotDetermined, // 还未授权,需要触发授权方法
    SFSpeechRecognizerAuthorizationStatusDenied, // 已被拒绝    
    SFSpeechRecognizerAuthorizationStatusRestricted, // 已被限制,例如家长控制等等 
    SFSpeechRecognizerAuthorizationStatusAuthorized, // 已允许    
} API_AVAILABLE(ios(10.0));

当获取到的状态是SFSpeechRecognizerAuthorizationStatusNotDetermined时,需要触发授权方法,授权API是:

[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程操作
    });
}];

值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码

最后添加上所有权限key的代码

<key>NSCalendarsUsageDescription</key>
<string>日历</string>
<key>NSCameraUsageDescription</key>
<string>需要获取您的摄像头信息</string>
<key>NSContactsUsageDescription</key>
<string>需要获取您的通讯录权限</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>“始终”定位权限</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>“使用应用期间”定位权限</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要获取您的麦克风权限</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要获取您的相册信息</string>
<key>NSRemindersUsageDescription</key>
<string>提醒事项</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>语音识别权限</string>

描述文字一定要说清楚作用,不然会被拒绝,拒绝,拒绝,当然这还要看审核人员的心情了。当事人已经被拒绝过了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270