zoukankan      html  css  js  c++  java
  • 指纹验证完整版处理小结

      在ios中指纹的使用相对比较简单,但是在使用的过程中遇到以下几个问题,故对指纹使用进行简单封装,以处理这些问题,问题如下:

        1、ios 9之后系统指纹被锁,系统不会主动弹出密码解锁的页面

        2、ios 10.*系统不区分指纹未录入和密码未设置的情况

      处理逻辑如下:

      

      处理部分代码如下:

    ----------------------------.h文件
    
    /*
     1、处理iOS 9.0之后,指纹被锁不会自动弹出密码解锁的情况;
     2、处理iOS 10.*系统不区分未录入指纹和未设置密码的情况;
     */
    #import <Foundation/Foundation.h>
    
    typedef NS_ENUM(NSInteger, TITouchIDVerificationError) {
        TITouchIDVerificationErrorLocalizedReason,
        TITouchIDVerificationErrorAuthFailMessage,
        TITouchIDVerificationErrorNotAvailableMessage,
        TITouchIDVerificationErrorNotEnrolledMessage,
        TITouchIDVerificationErrorLockOut,
        TITouchIDVerificationErrorPasscodeNotSetMessage,
        TITouchIDVerificationErrorUserCancel,
        TITouchIDVerificationErrorAppCancel,
        TITouchIDVerificationErrorUnknown
    };
    
    typedef NS_ENUM(NSInteger, TIVerificationStatus) {
        TIVerificationStatusSuccess,
        TIVerificationStatusPasswordNotSet,
        TIVerificationStatusNotEncrolled,
        TIVerificationStatusFailed,
        TIVerificationStatusFallback,
        TIVerificationStatusLockOut,
        TIVerificationStatusCancel,
        TIVerificationStatusError,
    };
    
    typedef void(^VerificationCompletion)(TIVerificationStatus status, NSError *error);
    
    @interface LYYTouchID : NSObject
    
    
    /**
     调用TouchID
    
     @param completion 验证完成,如果返回YES,验证成功;如果返回NO,验证失败(输入密码和指纹验证失败)
     */
    + (void)touchVerificationWithFallbackTitle:(NSString*)fallbackTitle completion:(VerificationCompletion)completion;
    @end
    
    
    ---------------------------.m文件
    
    #import "LYYTouchID.h"
    #import <UIKit/UIKit.h>
    #import <LocalAuthentication/LocalAuthentication.h>
    
    #define TI_IS_iOS_LATER(num)  ([UIDevice currentDevice].systemVersion.floatValue >= (num))
    #define TI_IS_iOS8_LATER  TI_IS_iOS_LATER(8.0)
    #define TI_IS_iOS9_LATER  TI_IS_iOS_LATER(9.0)
    #define TI_IS_iOS10_LATER  TI_IS_iOS_LATER(10.0)
    #define TI_IS_iOS11_LATER  TI_IS_iOS_LATER(11.0)
    
    NSString * const TouchIDLocalizedReason = @"请您验证已有TouchID";
    NSString * const TouchIDNotAvailableMessage = @"您当前设备不支持TouchID";
    NSString * const TouchIDNotEnrolledMessage = @"您当前没有录入指纹信息";
    NSString * const TouchIDNotCorrectMessage = @"您的指纹信息不匹配";
    NSString * const TouchIDPasscodeNotSetMessage = @"您当前没有设置密码";
    NSString * const TouchIDCancelMessage = @"您已取消验证TouchID";
    NSString * const TouchIDUnknownErrorMessage = @"出现未知错误";
    NSString * const TouchIDLockOutMessage = @"TouchID 被锁定";
    
    static BOOL _isTouchIDLocked;//用于存储第一遍canEvaluatePolicy检查到的指纹被锁的状态
    static BOOL _touchIDSecondCheck;//用于存储canEvaluatePolicy是否是第二次查询
    
    @interface LYYTouchID ()
    @end
    
    
    @implementation LYYTouchID
    
    #pragma mark - 验证
    + (void)touchVerificationWithFallbackTitle:(NSString*)fallbackTitle completion:(VerificationCompletion)completion{
        LAContext *context = [[LAContext alloc] init];
        context.localizedFallbackTitle = fallbackTitle?:@"";
        LAPolicy policy = [self setPolicy];
        
        NSError *notSupportError = nil;
        if ([context canEvaluatePolicy:policy error:&notSupportError]) {
            
            //处理10.*系统纯指纹策略不走passwordNotSet方法
            if (_touchIDSecondCheck&&TI_IS_iOS10_LATER&&!TI_IS_iOS11_LATER) {//第二次检测指纹是否可用(指纹+密码策略),且可以
                _touchIDSecondCheck = NO;
                completion(TIVerificationStatusNotEncrolled,[self returnErrorInfoWithErrorCode:LAErrorTouchIDNotEnrolled]);
                return;
            }
            
            //不是第二次检测指纹是否可用,直接进行验证
            [context evaluatePolicy:policy localizedReason:TouchIDLocalizedReason reply:^(BOOL success, NSError * _Nullable error) {
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (success) {
                        
                        if (TI_IS_iOS9_LATER&&_isTouchIDLocked) {//TouchID 解锁成功时,更改为纯指纹策略,验证TouchID
                            _isTouchIDLocked = NO;
                            [self touchVerificationWithFallbackTitle:fallbackTitle completion:completion];
                        }else{//ios9.0之前版本不支持密码策略直接返回信息
                            _isTouchIDLocked = NO;
                            completion(TIVerificationStatusSuccess,nil);
                        }
                    }
                    else {
                        int code = (int)error.code;
                        ////设置锁定状态为NO
                        _isTouchIDLocked = NO;
                        [self dealErrorWithErrorCode:code fallbackTitle:fallbackTitle complection:completion];
                    }
    
                });
                
            }];
        }else {
            
            [self dealErrorWithErrorCode:(int)notSupportError.code fallbackTitle:fallbackTitle complection:completion];
        }
    }
    #pragma mark - 设置指纹策略
    + (LAPolicy)setPolicy{
        LAPolicy policy;
        
        if (_touchIDSecondCheck&&TI_IS_iOS9_LATER){//已经查验过纯指纹策略,且纯指纹策略不支持,改变策略为指纹+密码进行二次验证
            policy = LAPolicyDeviceOwnerAuthentication;
            return policy;
        }
        if (_isTouchIDLocked&&TI_IS_iOS9_LATER) {//指纹被锁定且系统大于9.0,使用“指纹+密码”策略
            policy = LAPolicyDeviceOwnerAuthentication;
        }else{//使用“指纹”策略(默认是指纹策略)
            policy = LAPolicyDeviceOwnerAuthenticationWithBiometrics;
        }
        return policy;
    }
    #pragma mark - 处理不同错误
    + (void)dealErrorWithErrorCode:(int)code fallbackTitle:(NSString*)fallbackTitle complection:(VerificationCompletion)completion{
        
        switch (code) {
            case LAErrorUserFallback:
                completion(TIVerificationStatusFallback,[self returnErrorInfoWithErrorCode:code]);
                break;
                
            case LAErrorAuthenticationFailed:
                completion(TIVerificationStatusFailed,[self returnErrorInfoWithErrorCode:code]);
                break;
                
            case LAErrorSystemCancel:{
                _isTouchIDLocked = NO;
                _touchIDSecondCheck = NO;
            }
                break;
             
            case LAErrorPasscodeNotSet:
                _isTouchIDLocked = NO;
                _touchIDSecondCheck = NO;
                completion(TIVerificationStatusPasswordNotSet,[self returnErrorInfoWithErrorCode:code]);
                break;
                
            case LAErrorTouchIDNotAvailable:
                
                break;
      
            case LAErrorAppCancel:{
                _isTouchIDLocked = NO;
                _touchIDSecondCheck = NO;
            }
                break;
            case LAErrorUserCancel:
                _isTouchIDLocked = NO;
                _touchIDSecondCheck = NO;
                completion(TIVerificationStatusCancel,[self returnErrorInfoWithErrorCode:code]);
                break;
    
            default: {
                if (TI_IS_iOS9_LATER) {
                    if (code==LAErrorTouchIDLockout) {
                        //ios9.0更改为密码策略,解锁TouchID
                        _isTouchIDLocked = YES;
                        [self touchVerificationWithFallbackTitle:fallbackTitle completion:completion];
                        break;
    
                    }
                }
                if (TI_IS_iOS8_LATER&&!TI_IS_iOS11_LATER) {
                    if (code==LAErrorTouchIDNotEnrolled) {
                        //处理ios 10.*系统不走passwordNotSet
                        if (TI_IS_iOS10_LATER&&!_touchIDSecondCheck) {//ios 9.0之后,第一次返回指纹不可用的结果(这时是纯指纹策略)
                            _touchIDSecondCheck = YES;
                            [self touchVerificationWithFallbackTitle:fallbackTitle completion:completion];
                        }else{
                            //ios 9.0 之后是第二次返回不可用结果,此时采用的是指纹+密码策略,此时指纹确实不可用
                            //ios 9.0 之前,第一次返回指纹不可用的结果,此时直接返回指纹不可用的错误
                            _touchIDSecondCheck = NO;
                            completion(TIVerificationStatusNotEncrolled,[self returnErrorInfoWithErrorCode:code]);
                        }
                        
                        break;
                    }
                }
                if (@available(iOS 11.0, *)) {
                    if (code==LAErrorBiometryNotEnrolled) {
                        completion(TIVerificationStatusNotEncrolled,[self returnErrorInfoWithErrorCode:code]);
                        break;
                    }
                }
                
                completion(TIVerificationStatusError,[self returnErrorInfoWithErrorCode:code]);
            }
                break;
                
        }
    }
    
    #pragma mark - 生成error
    + (NSError *)returnErrorInfoWithErrorCode:(int)errorCode {
        
        if (TI_IS_iOS9_LATER) {
            if (errorCode == LAErrorAppCancel) {
                NSError *tempError = [NSError errorWithDomain:@"TouchIDVerfityDomain" code:TITouchIDVerificationErrorAppCancel userInfo:@{@"message":TouchIDCancelMessage}];
                return tempError;
            }
        }
        
        NSString *errorMessage = @"";
        NSUInteger errCode = 0;
        
        switch (errorCode) {
            case LAErrorTouchIDNotAvailable:
                errorMessage = TouchIDNotAvailableMessage;
                errCode = TITouchIDVerificationErrorNotAvailableMessage;
                break;
            case LAErrorAuthenticationFailed:
                errorMessage = TouchIDNotCorrectMessage;
                errCode = TITouchIDVerificationErrorAuthFailMessage;
                break;
            case LAErrorPasscodeNotSet:
                errorMessage = TouchIDPasscodeNotSetMessage;
                errCode = TITouchIDVerificationErrorPasscodeNotSetMessage;
                break;
            case LAErrorUserCancel:
                errorMessage = TouchIDCancelMessage;
                errCode = TITouchIDVerificationErrorUserCancel;
                break;
            default:
                if (TI_IS_iOS9_LATER) {
                    if (errorCode==LAErrorTouchIDLockout) {
                        errorMessage = TouchIDLockOutMessage;
                        errCode = TITouchIDVerificationErrorLockOut;
                        break;
                    }
                }
                if (TI_IS_iOS8_LATER&&!TI_IS_iOS11_LATER) {
                    if (errorCode==LAErrorTouchIDNotEnrolled) {
                        errorMessage = TouchIDNotEnrolledMessage;
                        errCode = TITouchIDVerificationErrorNotEnrolledMessage;
                        break;
                    }
                }
                if (@available(iOS 11.0, *)) {
                    if (errorCode==LAErrorBiometryNotEnrolled) {
                        errorMessage = TouchIDNotEnrolledMessage;
                        errCode = TITouchIDVerificationErrorNotEnrolledMessage;
                        break;
                    }
                }
                errorMessage = TouchIDUnknownErrorMessage;
                errCode = TITouchIDVerificationErrorUnknown;
                break;
        }
        
        NSError *tempError = [NSError errorWithDomain:@"TouchIDVerfityDomain" code:errCode userInfo:@{@"message":errorMessage}];
        //
        return tempError;
    }
    @end
  • 相关阅读:
    最小生成树与Prim算法
    图的存储——链式前向星
    *转载 Tarjan有向图详解
    图的连通性算法-Kosaraju
    最小花费8597
    PDF提取图片(错误纠正)
    字符串删除指定符号(不限位置)
    python迭代有限制,突破限制
    storm资源冲突
    storm单节点问题(转载)
  • 原文地址:https://www.cnblogs.com/sunjianfei/p/8669266.html
Copyright © 2011-2022 走看看