iOS开发获取系统权限弹窗的按钮回调的技巧

我们在日常开发中经常会遇到各种权限判定相关的逻辑,比如用户需要录音,需要录视频,就会用到手机的麦克风和摄像头,如果用户已经允许或禁止APP使用某项权限,我们可以直接获取这个状态,用户允许就执行后面的逻辑,用户禁止的话给用户一个提示,就像下面这样:

+ (void)takeCameraAuthorityStatusCompletion:(void(^)(BOOL allow))completion {
    //获取摄像头权限当前的状态
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if ((authStatus == AVAuthorizationStatusRestricted || authStatus ==AVAuthorizationStatusDenied)) {
        //用户禁止app 访问摄像头 或设置了家长控制 可以根据需求 给用户做一个友好的提示来让用户解除限制
        
    } else {
        //判断是真机还是模拟器
        if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) {
            if (completion) {
                completion(YES);
            }
        } else {
            NSLog(@"模拟器中无法打开照相机,请在真机中使用");
            if (completion) {
                completion(NO);
            }
        }
    }
}

但其实用户如果没有禁止的话 可能还有另外一种情况,就是用户从来没有对过这项权限做过设置(iOS系统中只有你在用到这项权限的时候系统才会提示你是否允许),这时候有可能用户之前就设置过允许,有可能根本就没设置过,比如针对摄像头权限,一共有四种情况

typedef NS_ENUM(NSInteger, AVAuthorizationStatus) {
    AVAuthorizationStatusNotDetermined = 0,//用户还未设置过
    AVAuthorizationStatusRestricted    = 1,//APP无法使用这项权限(比如手机设置了家长限制)
    AVAuthorizationStatusDenied        = 2,//用户不允许App使用这项权限
    AVAuthorizationStatusAuthorized    = 3,//用户允许App使用这项权限
}

如果用户已经设置过,我们可以直接获取状态来做相应的判断,那如果是第一次触发权限申请,我们就要在设置了这项权限之后,拿到设置的结果来做相应的处理,但目前在代码中还无法直接拿到权限申请的回调,就是说我们在工程里并不能直接做出判断,用户从权限弹框出现到点击弹框中的选项所需的时间是不确定的,所以我们也不能简单地设置延迟多少秒来获取这个状态,因为很可能用户会等很久才处理

在照片选择框架TZImagePickerController,作者利用定制器不停执行查询任务来解决了这一问题

- (void)judgeCameraAuthorityStatusCompletion:(void(^)(BOOL allow))completion {
    AVAuthorizationStatus authStatusTemp = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    //如果用户还没有设置过摄像头权限,系统会弹出弹框来让用户选择,此时需要不停查询这个状态,直到用户选择了是否允许
    if (authStatusTemp == AVAuthorizationStatusNotDetermined) {
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.2f target:self selector:@selector(getTheCameraAuth:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.judegeCameraBlock = completion;
    } else if ((authStatusTemp == AVAuthorizationStatusRestricted || authStatusTemp ==AVAuthorizationStatusDenied)) {
        //用户禁止app 访问摄像头 或设置了家长控制
        if (completion) {
            completion(NO);
        }
    } else if (authStatusTemp == AVAuthorizationStatusAuthorized) {
        //用户允许app 访问摄像头
        if (completion) {
            completion(YES);
        }
    } else {
        //理论上不会有这种情况
        if (completion) {
            completion(NO);
        }
    }
}

- (void)getTheCameraAuth:(NSTimer *)timer {
    AVAuthorizationStatus authStatusTemp = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if ((authStatusTemp == AVAuthorizationStatusRestricted || authStatusTemp ==AVAuthorizationStatusDenied)) {
        [timer invalidate];
        if (self.judegeCameraBlock) {
            self.judegeCameraBlock(NO);
        }
        timer = nil;
    } else if (authStatusTemp == AVAuthorizationStatusAuthorized) {
        [timer invalidate];
        if (self.judegeCameraBlock) {
            self.judegeCameraBlock(YES);
        }
        timer = nil;
    }
}

在合适的时机(比如即将要使用摄像头的时候)调用- (void)judgeCameraAuthorityStatusCompletion:(void(^)(BOOL allow))completion方法,该方法会在用户做出选择后的第一时间获取到当前的状态并完成回调

其他的权限比如,麦克风、相册、定位权限也可以按照这种逻辑来判断,前提是这个方法 一定要保证在App弹出权限请求弹框后执行,如果想直接判断的话,可以使用上面的+ (void)takeCameraAuthorityStatusCompletion:(void(^)(BOOL allow))completion方法,但此方法只能表明用户是否明确禁止了此项权限,如果没有禁止有可能是用户点击了允许,也有可能是用户从未进行过选择。

你可能感兴趣的:(iOS开发获取系统权限弹窗的按钮回调的技巧)