在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:¬SupportError]) { //处理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