iOS 相册、相机、通讯录 录音权限获取封装

在开发中,我们可能会遇到这样的情况,用户自己关闭了所有的操作权限,以后要使用我们的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];

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • 一、为什么要获取权限 在越来越注重个人隐私的今天,用户很多情况下希望自己能完全掌握自己手机应用对媒体信息的一些访问...
    wentianen阅读 14,420评论 1 23
  • 1.图层树 :Core Animation是一个复合引擎,它的职责就是尽可能快地组合屏幕上不同的可视内容,这个内容...
    passionCai阅读 95评论 0 0
  • 第一天我大概就要入坑了吧。 有喜欢读书的人喜欢书法的人喜欢音乐的人喜欢古风的人。 不论在哪一方面我都算不上专业但是...
    陌上人如玉l阅读 134评论 0 0
  • 十、出井入合 六十五难曰∶经言所出为井,所入为合,其法奈何?然所出为井,井者东方春也,万物之始生,故言所出为井也。...
    妙瑜的记事本阅读 629评论 0 0