在開發中,我們可能會遇到這樣的情況,用戶自己關閉了所有的操作權限,以后要使用我們的App,總是得不到想要的結果。這個時候,對用戶操作權限的獲取,并進行必要的提示就必不可少了。
84B2A9705B046412E1D8F9591830C8FB.png
蘋果對用戶權限邏輯的修改
在iOS10中,如果你的App想要訪問用戶的相機、相冊、麥克風、通訊錄等等權限,都需要進行相關的配置,不然會直接crash(閃退)。
需要在info.plist中添加App需要的一些設備權限。
<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>
那么在這種情況下,就需要對用戶權限的獲取狀態和邏輯進行修改。下邊是我對整個App用戶請求權限的封裝。代碼還是很簡單的。
用戶權限狀態的幾種枚舉類型
AuthorizationStatusNotDetermined // 用戶從未進行過授權等處理,首次訪問相應內容會提示用戶進行授權
AuthorizationStatusAuthorized = 0, // 用戶已授權,允許訪問
AuthorizationStatusDenied, // 用戶拒絕訪問
AuthorizationStatusRestricted, // 應用沒有相關權限,且當前用戶無法改變這個權限,比如:家長控制
常見的幾種可以獲取系統權限的對象
typedef NS_ENUM(NSInteger, KSystemPermissions) {
KAVMediaTypeVideo = 0, // 相機
KALAssetsLibrary, //相冊
KCLLocationManager, //地理位置信息
KAVAudioSession, //音頻
KABAddressBook //手機通訊錄
};
大致的思路就是根據 傳入的需要獲取權限的對象, 彈出響應的提示語,讓用戶根據需要決定是否去設置中開啟相應的權限。
由于代碼比較簡單,這里就大致提一下,具體可以將Demo 下載下來。
我寫的Demo地址: SystemAuthorizationManager。稍后會使用pods的形式,集成到工程中。
//
// SystemPermissionsManager.h
// SystemPermissionsManager
//
// Created by Kenvin on 2016/11/24.
// Copyright ? 2016年 上海方創金融股份信息服務有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, KSystemPermissions) {
KAVMediaTypeVideo = 0, // 相機
KALAssetsLibrary, //相冊
KCLLocationManager, //地理位置信息
KAVAudioSession, //音頻
KABAddressBook //手機通訊錄
};
@interface SystemPermissionsManager : NSObject
+ (instancetype)sharedManager ;
/**
* 根據場景選擇合適的提示系統權限類型
*
* @param systemPermissions 系統權限類型
*
* @return 是否具有權限
*/
- (BOOL)requestAuthorization:(KSystemPermissions)systemPermissions;
@end
//
// SystemPermissionsManager.m
// SystemPermissionsManager
//
// Created by Kenvin on 2016/11/24.
// Copyright ? 2016年 上海方創金融股份信息服務有限公司. All rights reserved.
//
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "SystemPermissionsManager.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <CoreLocation/CoreLocation.h>
#import <Photos/Photos.h>
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
#import <ContactsUI/ContactsUI.h>
#import "BlockAlertView.h"
static NSString *const APPNAME = @""; //填寫自己APP NAME
static SystemPermissionsManager *systemPermissionsManager = nil;
@interface SystemPermissionsManager ()<CLLocationManagerDelegate,UIAlertViewDelegate>
@property(nonatomic,strong) CLLocationManager *locationManager;
@end
@implementation SystemPermissionsManager
+ (instancetype)sharedManager {
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
systemPermissionsManager = [[SystemPermissionsManager alloc] init];
});
return systemPermissionsManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
systemPermissionsManager = [super allocWithZone:zone];
});
return systemPermissionsManager;
}
- (id)init {
self = [super init];
if (self) {
//如果不需要定位的話,請刪除與定位相關的代碼即可。
[self setup];
}
return self;
}
- (void)setup {
//定位
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter = 1.0;
if([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization]; // 永久授權
}
if ([CLLocationManager locationServicesEnabled]) {
if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 8.0) {
[_locationManager requestAlwaysAuthorization];
}
CLAuthorizationStatus status = CLLocationManager.authorizationStatus;
if (status == kCLAuthorizationStatusRestricted || status == kCLAuthorizationStatusDenied) {
}else{
}
}else{
}
}
-(id)copyWithZone:(struct _NSZone *)zone{
return systemPermissionsManager;
}
- (BOOL)requestAuthorization:(KSystemPermissions)systemPermissions{
switch (systemPermissions) {
case KAVMediaTypeVideo:{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
if(authStatus == ALAuthorizationStatusDenied){
NSString *tips = [NSString stringWithFormat:@"請在iPhone的”設置-隱私-相機“選項中,允許%@訪問你的手機相機",APPNAME];
[self executeAlterTips:tips isSupport:YES];
return NO;
}else if(authStatus == ALAuthorizationStatusRestricted ){
[self executeAlterTips:nil isSupport:NO];
return NO;
}else if(authStatus == ALAuthorizationStatusNotDetermined ){
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
}else{
}
}];
}
}
}
break;
case KALAssetsLibrary:{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
if ([UIDevice currentDevice].systemVersion.floatValue < 8.0) {
ALAuthorizationStatus authStatus = [ALAssetsLibrary authorizationStatus];
if ( authStatus ==ALAuthorizationStatusDenied){
//無權限
NSString *tips = [NSString stringWithFormat:@"請在iPhone的”設置-隱私-相冊“選項中,允許%@訪問你的手機相冊",APPNAME];
[self executeAlterTips:tips isSupport:YES];
return NO;
}else if (authStatus == ALAuthorizationStatusRestricted){
[self executeAlterTips:nil isSupport:NO];
return NO;
}
}else{
PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
if (authorizationStatus == PHAuthorizationStatusRestricted) {
[self executeAlterTips:nil isSupport:NO];
return NO;
}else if(authorizationStatus == PHAuthorizationStatusDenied){
NSString *tips = [NSString stringWithFormat:@"請在iPhone的”設置-隱私-相冊“選項中,允許%@訪問你的手機相冊",APPNAME];
[self executeAlterTips:tips isSupport:YES];
return NO;
}else if (authorizationStatus == PHAuthorizationStatusNotDetermined){
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
}];
}
}
}
}
break;
case KCLLocationManager:{
CLAuthorizationStatus authStatus = CLLocationManager.authorizationStatus;
if ( authStatus == kCLAuthorizationStatusDenied) {
NSString *tips = [NSString stringWithFormat:@"請在iPhone的”設置-隱私-定位“選項中,允許%@訪問你的定位",APPNAME];
[self executeAlterTips:tips isSupport:YES];
return NO;
}else if(authStatus == kCLAuthorizationStatusRestricted ){
[self executeAlterTips:nil isSupport:NO];
return NO;
}
}
break;
case KAVAudioSession:{
if (![self canRecord]) {
NSString *tips = [NSString stringWithFormat:@"請在iPhone的”設置-隱私-麥克風“選項中,允許%@訪問你的麥克風",APPNAME];
[self executeAlterTips:tips isSupport:YES];
return NO;
}
}
break;
case KABAddressBook:{
ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus();
NSString *tips = [NSString stringWithFormat:@"請在iPhone的”設置-隱私-聯系人“選項中,允許%@訪問你的手機通訊錄",APPNAME];
if ( authStatus ==kABAuthorizationStatusDenied){
//無權限
[self executeAlterTips:tips isSupport:YES];
return NO;
}else if (authStatus == kABAuthorizationStatusRestricted ){
[self executeAlterTips:nil isSupport:NO];
return NO;
}else if(authStatus == kABAuthorizationStatusNotDetermined){
__block ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if (addressBook == NULL) {
[self executeAlterTips:nil isSupport:NO];
return NO;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (granted) {
}else{
}
if (addressBook) {
CFRelease(addressBook);
addressBook = NULL;
}
});
}
}
break;
default:
break;
}
return YES;
}
- (BOOL)canRecord{
__block BOOL bCanRecord = YES;
if ([[UIDevice currentDevice] systemVersion].floatValue > 7.0){
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSession respondsToSelector:@selector(requestRecordPermission:)]) {
[audioSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
if (granted) {
bCanRecord = YES;
} else {
bCanRecord = NO;
}
}];
}
}
return bCanRecord;
}
- (void)executeAlterTips:(NSString *)alterTips isSupport:(BOOL)isSupport{
dispatch_async(dispatch_get_main_queue(), ^{
NSString *alterContent = @"";
if (isSupport) {
alterContent = alterTips;
[BlockAlertView alertWithTitle:alterContent
message:@""
cancelButtonWithTitle:@"取消"
cancelBlock:^{
} confirmButtonWithTitle:@"去設置" confrimBlock:^{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]
options:@{@"url":@""}
completionHandler:^(BOOL success) {
}];
}];
}else{
alterContent = @"權限受限";
[BlockAlertView alertWithTitle:alterContent
message:@""
cancelButtonWithTitle:nil
cancelBlock:^{
} confirmButtonWithTitle:@"確定"
confrimBlock:^{
}];
}
});
}
@end
#pragma clang diagnostic pop
如何使用,方法如下
[[SystemPermissionsManager sharedManager] requestAuthorization:KALAssetsLibrary];