zoukankan      html  css  js  c++  java
  • ios --指纹TouchID

      

      最近在做一套登录系统,包括指纹登录、手势登录以及账号密码登录,在此简单记录一下指纹的处理逻辑。

      


    指纹处理:
    1、处理iOS 9.0之后,指纹被锁不会自动弹出密码解锁的情况;
    2、处理iOS 10.*系统不区分未录入指纹和未设置密码的情况;
    流程图:此处有图,周末再画
     
     
     周末补上
     
     
     
    代码如下:
     
    .h:
     
    //  Created by ever on 17/3/7.
    //  Copyright © 2017年 ever. All rights reserved.
    //
    #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:
    //  Created by ever on 17/3/7.
    //  Copyright © 2017年 ever. All rights reserved.
     
     
    #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 _isTouchIDSecondCheck;//用于存储第一遍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&&_isTouchIDSecondCheck) {//TouchID 解锁成功时,更改为纯指纹策略,验证TouchID
                            _isTouchIDSecondCheck = NO;
                            [self touchVerificationWithFallbackTitle:fallbackTitle completion:completion];
                        }else{//ios9.0之前版本不支持密码策略直接返回信息
                            _isTouchIDSecondCheck = NO;
                            completion(TIVerificationStatusSuccess,nil);
                        }
                    }
                    else {
                        int code = (int)error.code;
                        ////设置锁定状态为NO
                        _isTouchIDSecondCheck = 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 (_isTouchIDSecondCheck&&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:{
                _isTouchIDSecondCheck = NO;
                _touchIDSecondCheck = NO;
            }
                break;
            
            case LAErrorPasscodeNotSet:
                _isTouchIDSecondCheck = NO;
                _touchIDSecondCheck = NO;
                completion(TIVerificationStatusPasswordNotSet,[self returnErrorInfoWithErrorCode:code]);
                break;
               
            case LAErrorTouchIDNotAvailable:
               
                break;
     
            case LAErrorAppCancel:{
                _isTouchIDSecondCheck = NO;
                _touchIDSecondCheck = NO;
            }
                break;
            case LAErrorUserCancel:
                _isTouchIDSecondCheck = NO;
                _touchIDSecondCheck = NO;
                completion(TIVerificationStatusCancel,[self returnErrorInfoWithErrorCode:code]);
                break;
     
            default: {
                if (TI_IS_iOS9_LATER) {
                    if (code==LAErrorTouchIDLockout) {
                        //ios9.0更改为密码策略,解锁TouchID
                        _isTouchIDSecondCheck = 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
     
     
     
  • 相关阅读:
    经管-7
    均衡价格和均衡产量以及偏分求导
    点弹性系数计算
    洛谷-P5703 【深基2.例5】苹果采购
    洛谷-P1616 疯狂的采药
    洛谷-P1049 装箱问题
    洛谷-P1048 采药
    洛谷-P1064 金明的预算方案
    操作系统启动
    mybatis中使用注解查询和使用xml配置文件查询相互对应关系
  • 原文地址:https://www.cnblogs.com/sunjianfei/p/7885927.html
Copyright © 2011-2022 走看看