iOS --- Touch ID指纹解锁
最近在项目中刚好用到了TouchId指纹解锁功能,之前也没有接触过,立马百度看看究竟是要如何使用,发现其实也不是很复杂。
文章后面有封装的工具方法,可以直接copy使用。
下面开始跟大家分享一下:
一、使用要点:
(1)需要导入库 LocalAuthentication.framework
(2)引入头文件 #import <LocalAuthentication/LocalAuthentication.h>
(3)指纹解锁只支持iOS 8及以上的版本
(4)如果指纹验证多次错误会被锁定,只能通过输入手机密码来重新启用。iOS 9 提供了一个方法,可以直接调起密码输入界面。
(5)所有操作必须要回到主线程,因为系统的验证是在子线程。
(6)所有的错误处理是通过一个枚举来判断处理的,具体作用看注释
二、代码要点
(1)这是判断系统版本是否大于iOS 8
if (!(MQ_CURRENT_DEVICE_SYSTEM_VERSION >= 8.0)) { result(NO, MQ_TOUCHID_ERROR_SYSTEM_NOT_SUPPORT); return; }
(2)判断是否可用
// 返回bool值 [authenContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]
(3)下面的就是重要的点 :
指纹解锁多次失败以后,系统会锁定TouchID硬件必须通过输入手机密码来解锁,如果系统是iOS8的话,TouchID被锁定以后只能通过重启手机来重新开启。
//系统提供的两个验证的枚举 typedef NS_ENUM(NSInteger, LAPolicy) { LAPolicyDeviceOwnerAuthenticationWithBiometrics NS_ENUM_AVAILABLE(NA, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0) = kLAPolicyDeviceOwnerAuthenticationWithBiometrics, LAPolicyDeviceOwnerAuthentication NS_ENUM_AVAILABLE(10_11, 9_0) = kLAPolicyDeviceOwnerAuthentication } NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);
kLAPolicyDeviceOwnerAuthentication 这个值只有在iOS9.0及以后才可以使用,利用这个值可以调出输入密码来解锁TouchID的界面。
[authenContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:TOUCHID_NOTICE_MESSAGE reply:^(BOOL success, NSError * _Nullable error) { if (success) { //已经重新解锁Touchid } }];
开始指纹解锁代码
[authenContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:TOUCHID_NOTICE_MESSAGE reply:^(BOOL success, NSError * _Nullable error) { if (success) { // 解锁成功 } }];
(4)看看系统的错误枚举
typedef NS_ENUM(NSInteger, LAError) { /// Authentication was not successful, because user failed to provide valid credentials. LAErrorAuthenticationFailed = kLAErrorAuthenticationFailed, /// Authentication was canceled by user (e.g. tapped Cancel button). LAErrorUserCancel = kLAErrorUserCancel, /// Authentication was canceled, because the user tapped the fallback button (Enter Password). LAErrorUserFallback = kLAErrorUserFallback, /// Authentication was canceled by system (e.g. another application went to foreground). LAErrorSystemCancel = kLAErrorSystemCancel, /// Authentication could not start, because passcode is not set on the device. LAErrorPasscodeNotSet = kLAErrorPasscodeNotSet, /// Authentication could not start, because Touch ID is not available on the device. LAErrorTouchIDNotAvailable NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotAvailable") = kLAErrorTouchIDNotAvailable, /// Authentication could not start, because Touch ID has no enrolled fingers. LAErrorTouchIDNotEnrolled NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotEnrolled") = kLAErrorTouchIDNotEnrolled, /// Authentication was not successful, because there were too many failed Touch ID attempts and /// Touch ID is now locked. Passcode is required to unlock Touch ID, e.g. evaluating /// LAPolicyDeviceOwnerAuthenticationWithBiometrics will ask for passcode as a prerequisite. LAErrorTouchIDLockout NS_ENUM_DEPRECATED(10_11, 10_13, 9_0, 11_0, "use LAErrorBiometryLockout") __WATCHOS_DEPRECATED(3.0, 4.0, "use LAErrorBiometryLockout") __TVOS_DEPRECATED(10.0, 11.0, "use LAErrorBiometryLockout") = kLAErrorTouchIDLockout, /// Authentication was canceled by application (e.g. invalidate was called while /// authentication was in progress). LAErrorAppCancel NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorAppCancel, /// LAContext passed to this call has been previously invalidated. LAErrorInvalidContext NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorInvalidContext, /// Authentication could not start, because biometry is not available on the device. LAErrorBiometryNotAvailable NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotAvailable, /// Authentication could not start, because biometry has no enrolled identities. LAErrorBiometryNotEnrolled NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotEnrolled, /// Authentication was not successful, because there were too many failed biometry attempts and /// biometry is now locked. Passcode is required to unlock biometry, e.g. evaluating /// LAPolicyDeviceOwnerAuthenticationWithBiometrics will ask for passcode as a prerequisite. LAErrorBiometryLockout NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryLockout, /// Authentication failed, because it would require showing UI which has been forbidden /// by using interactionNotAllowed property. LAErrorNotInteractive API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0), tvos(10.0)) = kLAErrorNotInteractive, } NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);
三、这是我封装的工具类
(1)MQTouchID.h文件
// // MQTouchID.h // Test // // Created by PasserMontanus on 2018/3/21. // Copyright © 2018年 lgl. All rights reserved. // #import <Foundation/Foundation.h> typedef NS_ENUM(NSInteger, MQ_TOUCHID_ERROR) { // 系统不支持 要大于 8.0 MQ_TOUCHID_ERROR_SYSTEM_NOT_SUPPORT = 0, // 验证成功 MQ_TOUCHID_ERROR_SUCCESS = 1, // 系统取消授权,如其他APP切入 MQ_TOUCHID_ERROR_SYSTEM_CANCEL = -4, // 用户取消验证Touch ID MQ_TOUCHID_ERROR_USER_CANCEL = -2, // 用户选择输入密码 MQ_TOUCHID_ERROR_USER_FALLBACK = -3, //授权失败 MQ_TOUCHID_ERROR_FAILED = -1, //系统未设置密码 这个密码在用户指纹多次验证失败的时候要用他来重新激活 MQ_TOUCHID_ERROR_PASSCODE_NOT_SET = -5, //设备Touch ID不可用,例如未打开 MQ_TOUCHID_ERROR_NOT_AVAILABLE = -6, //设备Touch ID不可用,用户没有录入指纹 MQ_TOUCHID_ERROR_NOT_ENROLLED = -7, //身份验证失败,因为它需要显示已被禁止的UI MQ_TOUCHID_ERROR_NOT_INTERACTIVE = -1004, // 设备Touch ID被锁定,输入错误的次数过多 这个时候需要密码来重新激活 MQ_TOUCHID_ERROR_LOCKOUT = -8 , //应用程序已取消身份验证 MQ_TOUCHID_ERROR_APP_CANCEL = -9, // 传递给此调用的LAContext先前已失效。 MQ_TOUCHID_ERROR_INVALID_CONTEXT = -10 }; typedef void(^MQTouchIDResult)(BOOL isSuccess, MQ_TOUCHID_ERROR error_code); @interface MQTouchID : NSObject /** 开始验证 TouchID 指纹解锁 (需要导入 LocalAuthentication.framework) 注意: 结果回调以后的操作都需要回到主线程 这个验证是在子线程里面执行的 */ + (void)validateTouchID:(MQTouchIDResult)result; @end
(2)MQTouchID.m文件
// // MQTouchID.m // Test // // Created by PasserMontanus on 2018/3/21. // Copyright © 2018年 lgl. All rights reserved. // #import "MQTouchID.h" #import <LocalAuthentication/LocalAuthentication.h> #define MQ_CURRENT_DEVICE_SYSTEM_VERSION ([[UIDevice currentDevice]systemVersion].doubleValue) static NSString * TOUCHID_NOTICE_MESSAGE = @"通过Home键验证已有的手机指纹"; static NSString * TOUCHID_NOTICE_RESTART_MESSAGE = @"重新开启TouchID功能"; @implementation MQTouchID + (void)validateTouchID:(MQTouchIDResult)result { if (!(MQ_CURRENT_DEVICE_SYSTEM_VERSION >= 8.0)) { result(NO, MQ_TOUCHID_ERROR_SYSTEM_NOT_SUPPORT); return; } LAContext *authenContext = [[LAContext alloc]init]; NSError* error = nil; if ([authenContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { // 可用 [self startValidateTouchID:authenContext result:result]; } else { // 不可用 MQ_TOUCHID_ERROR erroCode = [self errorCode:error.code]; [self processingTouchIdError:authenContext erroCode:erroCode result:result]; } } + (void)startValidateTouchID:(LAContext *)authenContext result:(MQTouchIDResult)result { [authenContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:TOUCHID_NOTICE_MESSAGE reply:^(BOOL success, NSError * _Nullable error) { if (success) { result(YES,MQ_TOUCHID_ERROR_SUCCESS); } else { MQ_TOUCHID_ERROR erroCode = [self errorCode:error.code]; [self processingTouchIdError:authenContext erroCode:erroCode result:result]; } }]; } + (void)processingTouchIdError:(LAContext *)authenContext erroCode:(MQ_TOUCHID_ERROR)erroCode result:(MQTouchIDResult)result { if (@available(iOS 9.0, *)) { if (erroCode == MQ_TOUCHID_ERROR_LOCKOUT) { [authenContext evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:TOUCHID_NOTICE_RESTART_MESSAGE reply:^(BOOL success, NSError * _Nullable error) { if (success) { [self validateTouchID:result]; } else { result(NO, MQ_TOUCHID_ERROR_USER_CANCEL); } }]; } else { result(NO, erroCode); } } else { result(NO, erroCode); } } + (MQ_TOUCHID_ERROR)errorCode:(NSInteger )errorCode { switch (errorCode) { case LAErrorSystemCancel:{ // 系统取消授权,如其他APP切入 return MQ_TOUCHID_ERROR_SYSTEM_CANCEL; break; } case LAErrorUserCancel:{ // 用户取消验证Touch ID return MQ_TOUCHID_ERROR_USER_CANCEL; break; } case LAErrorUserFallback:{ // 用户选择输入密码 return MQ_TOUCHID_ERROR_USER_FALLBACK; break; } case LAErrorAuthenticationFailed:{ // //授权失败 return MQ_TOUCHID_ERROR_FAILED; break; } case LAErrorPasscodeNotSet: { //系统未设置密码 这个密码在用户指纹多次验证失败的时候要用他来重新激活 return MQ_TOUCHID_ERROR_PASSCODE_NOT_SET; break; } case LAErrorTouchIDNotAvailable: { //设备Touch ID不可用,例如未打开 return MQ_TOUCHID_ERROR_NOT_AVAILABLE; break; } case LAErrorTouchIDNotEnrolled: { //设备Touch ID不可用,用户没有录入指纹 return MQ_TOUCHID_ERROR_NOT_ENROLLED; break; } case LAErrorNotInteractive: { // 身份验证失败,因为它需要显示已被禁止的UI return MQ_TOUCHID_ERROR_NOT_INTERACTIVE; break; } default:{ if (@available(iOS 9.0, *)) { if (errorCode == LAErrorTouchIDLockout) { // 设备Touch ID被锁定,输入错误的次数过多 这个时候需要密码来重新激活 return MQ_TOUCHID_ERROR_LOCKOUT; break; } else { if (errorCode == LAErrorInvalidContext) { return MQ_TOUCHID_ERROR_INVALID_CONTEXT; break; } else if (errorCode == LAErrorAppCancel) { return MQ_TOUCHID_ERROR_APP_CANCEL; break; } else { return MQ_TOUCHID_ERROR_FAILED; break; } } } else { return MQ_TOUCHID_ERROR_FAILED; break; } } } } @end
四、最后结语
(1)最后的结果回调以后的操作一定要在主线程,系统验证在子线程进行
(2)以上就是我的一点小总结,欢迎大家指正。