自从iOS8增加了权限需要征得用户同意后,后续iOS对权限的要求越来严格,记录一下各种权限的获取方法
1、定位权限(info.plist需要添加LocationWhenInUseUsageDescription + LocationAlwaysUsageDescription)
需要获取用户此时此刻的位置信息的时候需要使用到定位权限。
使用到了#import
权限状态获取方法是:
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
权限状态获取方法是:
此时要区分系统版本获取,在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
请求录音权限通知的API方法:
AVAudioSession * audioSession = [AVAudioSession sharedInstance];
[audioSession requestRecordPermission:^(BOOL granted) {
// granted 代表允许与否
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程
});
}];
值得注意的是,此时block回调是在任意线程中的,所以需要回到主线程内处理其他代码
4、相机权限(info.plist需要添加CameraUsageDescription)
相机权限就要使用#import
获取当前权限状态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
获取当前相册权限状态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
获取通讯录权限状态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
获取当前权限状态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
获取当前权限状态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的代码
NSCalendarsUsageDescription
日历
NSCameraUsageDescription
需要获取您的摄像头信息
NSContactsUsageDescription
需要获取您的通讯录权限
NSLocationAlwaysUsageDescription
“始终”定位权限
NSLocationWhenInUseUsageDescription
“使用应用期间”定位权限
NSMicrophoneUsageDescription
需要获取您的麦克风权限
NSPhotoLibraryUsageDescription
需要获取您的相册信息
NSRemindersUsageDescription
提醒事项
NSSpeechRecognitionUsageDescription
语音识别权限
描述文字一定要说清楚作用,不然会被拒绝,拒绝,拒绝,当然这还要看审核人员的心情了。当事人已经被拒绝过了