背景
iOS的安全机制——沙盒限制了应用程序执行各种操作的权限。沙盒实际就是程序的系统文件目录,非代码文件都在此保存,例如图片、图标、视频、plist文件、文本文件,每个iOS程序只能访问自己沙盒中的东西,访问其他沙盒需要权限,它相对封闭、独立,使得iOS环境较为稳定。
iOS系统自iOS7.0之后,不同阶段的系统版本的权限特征或多或少都有所差异。若软件没有做好权限相应的限制适配,在提交APP Store审核时会被拒绝上线。例如在iOS10系统中,如果没有根据更新的权限要求在info.plist中进行声明而访问了隐私数据,在Xcode8中打开编译的话,会发生crash.
权限机制
Android系统对权限的隐私危害性进行三级划分,分为普通权限、特殊权限、危险权限。而iOS系统没有这些分类,基本采用第一次使用某功能就请求权限,之后除非在隐私中关闭该应用的该权限,否则该程序将一直拥有该权限。
基础知识
iOS13.1.1所有的权限:参照此图,iOS应用申请的主要权限有:
- 定位服务
- 通讯录
- 日历
- 提醒事项
- 照片
- 蓝牙
- 麦克风
- 语音识别(iOS10)
- 相机
- 健康(iOS8.0)
- Home kit(iOS8.0)
- 媒体与Apple Music(iOS9.0)
- 文件与文件夹(iOS12.0)
- 运动与健身
权限的状态:
- 用户从未进行过授权等处理,首次访问相应内容会提示用户进行授权
- 已授权
- 拒绝
- 应用没有相关权限,且当前用户无法改变这个权限,比如:家长控制
- 硬件等不支持
操作:
- 检查授权状态
-
请求授权
具体代码:
- 定位服务
-
获取状态
BOOL enable = [CLLocationManager locationServicesEnabled];//是否可用 NSInteger state = [CLLocationManager authorizationStatus];//授权状态
-
申请权限
self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; [self.locationManager requestAlwaysAuthorization]; [self.locationManager requestWhenInUseAuthorization];
-
- 通讯录
-
获取状态
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
-
申请权限
CNContactStore *contactStore = [[CNContactStore alloc] init]; [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { }];
-
- 日历
-
获取状态
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
-
申请权限
EKEventStore *store = [[EKEventStore alloc] init]; [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) { }];
-
- 提醒事项
-
获取状态
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder];
-
申请权限
EKEventStore *store = [[EKEventStore alloc] init]; [store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError * _Nullable error) { }];
-
- 照片
-
获取状态
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { if (_isiOS8_Or_Later_) { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; } else { // iOS7 - iOS8 ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; } } else { NSLog(@"相册不可用!"); }
-
申请权限
if (_isiOS8_Or_Later_) { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { }]; } else { ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init]; [assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { } failureBlock:^(NSError *error) { }]; }
-
- 蓝牙
-
获取状态
self.cbCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; #pragma mark - CBCentralManagerDelegate - (void)centralManagerDidUpdateState:(CBCentralManager *)central{ CBManagerState state = central.state; } }
申请权限
-
- 麦克风
-
获取状态
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
-
申请权限
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { }];
-
- 语音识别
-
获取状态
SFSpeechRecognizerAuthorizationStatus status = [SFSpeechRecognizer authorizationStatus];
-
申请权限
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) { }];
-
- 相机
-
获取状态
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; }
-
申请权限
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { }];
-
- 健康
-
获取状态
if ([HKHealthStore isHealthDataAvailable]) { self.healthStore = [[HKHealthStore alloc] init]; // 以心率 HKQuantityTypeIdentifierHeartRate 为例子 HKQuantityType *heartRateType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; HKAuthorizationStatus status = [self.healthStore authorizationStatusForType:heartRateType]; }else{ NSLog(@"unavailable"); // Health data is not avaliable on all device. }
-
申请权限
[self.healthStore requestAuthorizationToShareTypes:typeSet readTypes:typeSet completion:^(BOOL success, NSError * _Nullable error) { }];
-
- Home Kit
-
获取状态
self.homeManager = [[HMHomeManager alloc] init]; self.homeManager.delegate = self; #pragma mark - HMHomeManagerDelegate - (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager{ if (manager.homes.count > 0) { } }
-
申请权限
[manager addHomeWithName:@"Test Home" completionHandler:^(HMHome * _Nullable home, NSError * _Nullable error) { }];
-
- 媒体与Apple Music(ios(9.3))
-
获取状态
SKCloudServiceAuthorizationStatus status = [SKCloudServiceController authorizationStatus];
-
申请权限
[SKCloudServiceController requestAuthorization:^(SKCloudServiceAuthorizationStatus status) { }];
-
- 文件与文件夹
-
拷贝模式:将文档拷贝到自己项目中
//打开项目中的info.plist,添加“Document Types”键值 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{ }
-
存储模式:将文档存储到“文件”中
//打开项目中的info.plist,添加“Supports Document Browser”键值 UIDocumentPickerViewController * controller = [[UIDocumentPickerViewController alloc]initWithDocumentTypes:[@""] inMode:UIDocumentPickerModeOpen]; controller.delegate = self; [self presentViewController:controller animated:YES completion:nil];
-
- 运动与健身
-
获取状态
if( [CMMotionActivityManager isActivityAvailable]){ CMAuthorizationStatus status = [CMMotionActivityManager authorizationStatus]; }
-
申请权限
self.cmManager = [[CMMotionActivityManager alloc] init]; self.motionActivityQueue = [[NSOperationQueue alloc] init]; [self.cmManager startActivityUpdatesToQueue:self.motionActivityQueue withHandler:^(CMMotionActivity *activity) { }];
-