前言

关于系统权限的获取,相信大家都不陌生,可是其中蕴含的知识确实不少。
怎样向用户索取权限是非常重要的。例如LBS类的应用,如果在索取权限时遭到用户的拒*,那么该应用基本等同于无用了,更坏的是,点击“不允许”是很轻松的,而要撤销这个决定则不太容易,用户至少需要以下五步,一次性成功获取权限的重要性不言而喻,


关于这一点,好的设置可以概括为这样:

除非当前确实需要,否则不要向用户索取权限。
索取权限时要让用户明确的了解授权后的好处是什么。

权限分类

  • 联网权限
  • 相册权限
  • 相机、麦克风权限
  • 定位权限
  • 推送权限
  • 通讯录权限
  • 日历、备忘录权限

联网权限

引入头文件 @import CoreTelephony;
应用启动后,检测应用中是否有联网权限

  1. typedef NS_ENUM(NSUInteger, CTCellularDataRestrictedState) {
  2. kCTCellularDataRestrictedStateUnknown,//权限未知
  3. kCTCellularDataRestricted,//权限被关闭,
  4. kCTCellularDataNotRestricted//权限开启
  5. };
  6. 使用时需要注意的关键点:
  7. CTCellularData 只能检测蜂窝权限,不能检测WiFi权限。
  8. 一个CTCellularData实例新建时,restrictedState是kCTCellularDataRestrictedStateUnknown,
  9. 之后在cellularDataRestrictionDidUpdateNotifier里会有一次回调,此时才能获取到正确的权限状态。
  10. 当用户在设置里更改了app的权限时,cellularDataRestrictionDidUpdateNotifier会收到回调,如果要停止监听,
  11. 必须将cellularDataRestrictionDidUpdateNotifier设置为nil
  12. 赋值给cellularDataRestrictionDidUpdateNotifier的block并不会自动释放,
  13. 即便你给一个局部变量的CTCellularData实例设置监听,当权限更改时,还是会收到回调,所以记得将block置nil
  14. CTCellularData *cellularData = [[CTCellularData alloc]init];
  15. cellularData.cellularDataRestrictionDidUpdateNotifier = ^(CTCellularDataRestrictedState state)
  16. { //获取联网状态 switch (state)
  17. {
  18. case kCTCellularDataRestricted: NSLog(@”Restricrted”); break;
  19. case kCTCellularDataNotRestricted: NSLog(@”Not Restricted”); break;
  20. //未知,*次请求
  21. case kCTCellularDataRestrictedStateUnknown: NSLog(@”Unknown”); break;
  22. default: break;
  23. };
  24. };

查询应用是否有联网功能

  1. CTCellularData *cellularData = [[CTCellularData alloc]init];
  2. CTCellularDataRestrictedState state = cellularData.restrictedState;
  3. switch (state) {
  4. case kCTCellularDataRestricted: NSLog(@”Restricrted”); break;
  5. case kCTCellularDataNotRestricted: NSLog(@”Not Restricted”); break;
  6. case kCTCellularDataRestrictedStateUnknown: NSLog(@”Unknown”); break; default: break;
  7. }

注意:当应用被设置为不联网,使用的时候,系统会自动弹出警告“xxxx 已被关闭网络”点击可以去设置,自动跳转到设置中心里。
iOS10 国行机*次安装App时会有一个权限弹框弹出,在允许之前是没有网络的,网上对于现状已有描述和解决方法:
(1)在引导页中诱导出网络权限弹框,这样就不会影响到之后应用的网络请求。
(2)允许用户手动重新请求。出现数据空白时,如果在空白页面上有“重新加载”的按钮。
(3) 允许用户手动重新请求。出现数据空白时,如果在空白页面上有“重新加载”的按钮。

相册权限–iOS 9.0之前

导入头文件@import AssetsLibrary;
检查是否有相册权限

  1. ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
  2. switch (status) {
  3. case ALAuthorizationStatusAuthorized: NSLog(@“Authorized”); break;
  4. case ALAuthorizationStatusDenied: NSLog(@“Denied”); break;
  5. case ALAuthorizationStatusNotDetermined: NSLog(@“not Determined”); break;
  6. case ALAuthorizationStatusRestricted: NSLog(@“Restricted”); break; default: break;
  7. }

相册权限–iOS 8.0之后

导入头文件@import Photos;
检查是否有相册权限

  1. PHAuthorizationStatus photoAuthorStatus = [PHPhotoLibrary authorizationStatus];
  2. switch (photoAuthorStatus) {
  3. case PHAuthorizationStatusAuthorized: NSLog(@“Authorized”); break;
  4. case PHAuthorizationStatusDenied: NSLog(@“Denied”); break;
  5. case PHAuthorizationStatusNotDetermined: NSLog(@“not Determined”); break;
  6. case PHAuthorizationStatusRestricted: NSLog(@“Restricted”); break; default: break;}

获取相册权限

  1. [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
  2. if (status == PHAuthorizationStatusAuthorized)
  3. { NSLog(@“Authorized”); }
  4. else{ NSLog(@“Denied or Restricted”);
  5. } }];

相机和麦克风权限

导入头文件@import AVFoundation;
检查是否有相机或麦克风权限

  1. AVAuthorizationStatus AVstatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];//相机权限
  2. AVAuthorizationStatus AVstatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];//麦克风权限
  3. switch (AVstatus) {
  4. //允许状态
  5. case AVAuthorizationStatusAuthorized: NSLog(@”Authorized”); break;
  6. //不允许状态,可以弹出一个alertview提示用户在隐私设置中开启权限
  7. case AVAuthorizationStatusDenied: NSLog(@”Denied”); break;
  8. //未知,*次申请权限
  9. case AVAuthorizationStatusNotDetermined: NSLog(@”not Determined”); break;
  10. //此应用程序没有被授权访问,可能是家长控制权限
  11. case AVAuthorizationStatusRestricted: NSLog(@”Restricted”); break; default: break;
  12. }

获取相机或麦克风权限

  1. [AVCaptureDevice requestAccessForMediaType:
  2. AVMediaTypeVideo completionHandler:^(BOOL granted) {//相机权限
  3. if (granted) { NSLog(@“Authorized”); }
  4. else{ NSLog(@“Denied or Restricted”); }}];
  5. [AVCaptureDevice requestAccessForMediaType:
  6. AVMediaTypeAudio completionHandler:^(BOOL granted)
  7. {//麦克风权限
  8. if (granted) { NSLog(@“Authorized”); }
  9. else{ NSLog(@“Denied or Restricted”);
  10. }}];

定位权限

导入头文件@import CoreLocation;
由于iOS8.0之后定位方法的改变,需要在info.plist中进行配置;

配置文件

检查是否有定位权限

  1. BOOL isLocation = [CLLocationManager locationServicesEnabled];
  2. if (!isLocation) { NSLog(@”not turn on the location”);}
  3. CLAuthorizationStatus CLstatus = [CLLocationManager authorizationStatus];
  4. switch (CLstatus) {
  5. case kCLAuthorizationStatusAuthorizedAlways: NSLog(@”Always Authorized”); break;
  6. case kCLAuthorizationStatusAuthorizedWhenInUse: NSLog(@”AuthorizedWhenInUse”); break;
  7. case kCLAuthorizationStatusDenied: NSLog(@”Denied”); break;
  8. case kCLAuthorizationStatusNotDetermined: NSLog(@”not Determined”); break;
  9. case kCLAuthorizationStatusRestricted: NSLog(@”Restricted”); break; default: break;
  10. }

获取定位权限

  1. 这里有一个细节要注意, CLLocationManager 实例必须是全局的变量,否则授权提示弹框会一闪而过,不会一直显示。
  2. manager = [[CLLocationManager alloc] init];
  3. manager.delegate= self;
  4. [manager requestAlwaysAuthorization];//一直获取定位信息
  5. [manager requestWhenInUseAuthorization];//使用的时候获取定位信息

在代理方法中查看权限是否改变

  1. – (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
  2. {
  3. switch (status) {
  4. case kCLAuthorizationStatusAuthorizedAlways: NSLog(@“Always Authorized”); break;
  5. case kCLAuthorizationStatusAuthorizedWhenInUse: NSLog(@“AuthorizedWhenInUse”); break;
  6. case kCLAuthorizationStatusDenied: NSLog(@“Denied”); break;
  7. case kCLAuthorizationStatusNotDetermined: NSLog(@“not Determined”); break;
  8. case kCLAuthorizationStatusRestricted: NSLog(@“Restricted”); break; default: break;
  9. }}

推送权限

检查是否有通讯权限

  1. UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings];
  2. switch (settings.types) {
  3. case UIUserNotificationTypeNone: NSLog(@”None”); break;
  4. case UIUserNotificationTypeAlert: NSLog(@”Alert Notification”); break;
  5. case UIUserNotificationTypeBadge: NSLog(@”Badge Notification”); break;
  6. case UIUserNotificationTypeSound: NSLog(@”sound Notification'”); break; default: break;
  7. }

获取推送权限

  1. UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge categories:nil];
  2. [[UIApplication sharedApplication] registerUserNotificationSettings:setting];

通讯录权限

iOS9.0之前
导入头文件 @import AddressBook;
检查是否有通讯录权限

  1. ABAuthorizationStatus ABstatus = ABAddressBookGetAuthorizationStatus();
  2. switch (ABstatus) {
  3. case kABAuthorizationStatusAuthorized: NSLog(@”Authorized”); break;
  4. case kABAuthorizationStatusDenied: NSLog(@”Denied'”); break;
  5. case kABAuthorizationStatusNotDetermined: NSLog(@”not Determined”); break;
  6. case kABAuthorizationStatusRestricted: NSLog(@”Restricted”); break; default: break;
  7. }
  8. 获取通讯录权限
  9. ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
  10. ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
  11. if (granted)
  12. { NSLog(@”Authorized”);
  13. CFRelease(addressBook);
  14. }else{ NSLog(@”Denied or Restricted”);
  15. }});
  16. iOS9.0及以后
  17. 导入头文件 **@import Contacts;**
  18. 检查是否有通讯录权限
  19. CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
  20. switch (status) {
  21. case CNAuthorizationStatusAuthorized: { NSLog(@”Authorized:”); } break;
  22. case CNAuthorizationStatusDenied:{ NSLog(@”Denied”); } break;
  23. case CNAuthorizationStatusRestricted:{ NSLog(@”Restricted”); } break;
  24. case CNAuthorizationStatusNotDetermined:{ NSLog(@”NotDetermined”); } break;
  25. }
  26. 查询是否获取通讯录权限
  27. CNContactStore *contactStore = [[CNContactStore alloc] init]; [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
  28. if (granted) { NSLog(@”Authorized”); }
  29. else{ NSLog(@”Denied or Restricted”); }
  30. }];

日历、备忘录权限

导入头文件
检查是否有日历或者备忘录权限

  1. typedef NS_ENUM(NSUInteger, EKEntityType) { EKEntityTypeEvent,//日历 EKEntityTypeReminder //备忘 };
  2. EKAuthorizationStatus EKstatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
  3. switch (EKstatus) {
  4. case EKAuthorizationStatusAuthorized: NSLog(@”Authorized”); break;
  5. case EKAuthorizationStatusDenied: NSLog(@”Denied'”); break;
  6. case EKAuthorizationStatusNotDetermined: NSLog(@”not Determined”); break;
  7. case EKAuthorizationStatusRestricted: NSLog(@”Restricted”);
  8. break;
  9. default: break;
  10. }
  11. 查询是否获取日历或备忘录权限
  12. EKEventStore *store = [[EKEventStore alloc]init];
  13. [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
  14. if (granted) {
  15. NSLog(@”Authorized”); }
  16. else{ NSLog(@”Denied or Restricted”); }