zoukankan      html  css  js  c++  java
  • 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)以上就是我的一点小总结,欢迎大家指正。

  • 相关阅读:
    124. Binary Tree Maximum Path Sum
    99. Recover Binary Search Tree
    255. Verify Preorder Sequence in Binary Search Tree
    [LeetCode] 79. Word Search Java
    [LeetCode] 78. Subsets Java
    [LeetCode] 77. Combinations Java
    [LeetCode] 52. N-Queens II Java
    [LeetCode] 51. N-Queens Java
    [LeetCode] 47. Permutations II Java
    [LeetCode] 46. Permutations Java
  • 原文地址:https://www.cnblogs.com/ljmaque/p/TouchID.html
Copyright © 2011-2022 走看看