请选择 进入手机版 | 继续访问电脑版
MSIPO技术圈 首页 IT技术 查看内容

flutter开发实战-指纹、面容ID验证插件实现

2023-07-13

flutter开发实战-指纹、面容ID验证插件实现
在iOS开发中,经常出现需要指纹、面容ID验证的功能。

指纹、面容ID是一种基于用生物识别技术,通过扫描用户的面部特征来验证用户身份。

一、效果图

在这里插入图片描述
在这里插入图片描述

二、iOS指纹、面容ID验证

在iOS中实现指纹、面容ID验证功能,步骤如下

2.1 info.plist配置

在info.plist中配置允许访问FACE ID权限

<key>NSFaceIDUsageDescription</key>
<string>允许设备访问Face ID</string>

2.2 引入LocalAuthentication

在代码中引入#import <LocalAuthentication/LocalAuthentication.h>

具体代码实现如下

SDAuthID.h

#import <Foundation/Foundation.h>
#import <LocalAuthentication/LocalAuthentication.h>

/**
 *  设备支持的生物验证方式
 */
typedef NS_ENUM(NSUInteger, SDAuthIDSupportType) {
    /**
     *  支持TouchID验证
     */
    SDAuthIDSupportTypeTouchID = 1,
    /**
     *  支持FaceID验证
     */
    SDAuthIDSupportTypeFaceID,
    /**
     *  不支持支持验证
     */
    SDAuthIDSupportTypeNone,
};

/**
 *  TouchID/FaceID 状态
 */
typedef NS_ENUM(NSUInteger, SDAuthIDState){
    
    /**
     *  当前设备不支持TouchID/FaceID
     */
    SDAuthIDStateNotSupport = 0,
    /**
     *  TouchID/FaceID 验证成功
     */
    SDAuthIDStateSuccess = 1,
    
    /**
     *  TouchID/FaceID 验证失败
     */
    SDAuthIDStateFail = 2,
    /**
     *  TouchID/FaceID 被用户手动取消
     */
    SDAuthIDStateUserCancel = 3,
    /**
     *  用户不使用TouchID/FaceID,选择手动输入密码
     */
    SDAuthIDStateInputPassword = 4,
    /**
     *  TouchID/FaceID 被系统取消 (如遇到来电,锁屏,按了Home键等)
     */
    SDAuthIDStateSystemCancel = 5,
    /**
     *  TouchID/FaceID 无法启动,因为用户没有设置密码
     */
    SDAuthIDStatePasswordNotSet = 6,
    /**
     *  TouchID/FaceID 无法启动,因为用户没有设置TouchID/FaceID
     */
    SDAuthIDStateTouchIDNotSet = 7,
    /**
     *  TouchID/FaceID 无效
     */
    SDAuthIDStateTouchIDNotAvailable = 8,
    /**
     *  TouchID/FaceID 被锁定(连续多次验证TouchID/FaceID失败,系统需要用户手动输入密码)
     */
    SDAuthIDStateTouchIDLockout = 9,
    /**
     *  当前软件被挂起并取消了授权 (如App进入了后台等)
     */
    SDAuthIDStateAppCancel = 10,
    /**
     *  当前软件被挂起并取消了授权 (LAContext对象无效)
     */
    SDAuthIDStateInvalidContext = 11,
    /**
     *  系统版本不支持TouchID/FaceID (必须高于iOS 8.0才能使用)
     */
    SDAuthIDStateVersionNotSupport = 12
};

typedef void (^SDAuthIDStateBlock)(SDAuthIDState state, NSError *error);

 SDAuthID : NSObject

+ (instancetype)sharedInstance;

/**
 判断设备支持哪种认证方式 TouchID & FaceID
 */
- (SDAuthIDSupportType)canSupportBiometrics;

/**
 * 启动TouchID/FaceID进行验证
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthIDWithDescription:(NSString *)description
           localizedFallbackTitle:(NSString *)localizedFallbackTitle
                            block:(SDAuthIDStateBlock)block;

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthTouchIDWithDescription:(NSString *)description
                localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                 block:(SDAuthIDStateBlock)block;

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthFaceIDWithDescription:(NSString *)description
               localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                block:(SDAuthIDStateBlock)block;


实现的代码

SDAuthID.m

#import "SDAuthID.h"

 SDAuthID

+ (instancetype)sharedInstance {
    static SDAuthID *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[SDAuthID alloc] init];
    });
    return instance;
}

/**
 * 启动TouchID/FaceID进行验证
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthIDWithDescription:(NSString *)description
           localizedFallbackTitle:(NSString *)localizedFallbackTitle
                            block:(SDAuthIDStateBlock)block {
    
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"系统版本不支持TouchID/FaceID (必须高于iOS 8.0才能使用)");
            block(SDAuthIDStateVersionNotSupport, nil);
        });
        return;
    }
    
    
    LAContext *context = [[LAContext alloc] init];
    // 认证失败提示信息,为 @"" 则不提示
    context.localizedFallbackTitle = localizedFallbackTitle;
    
    NSError *error = nil;
    
    // LAPolicyDeviceOwnerAuthenticationWithBiometrics: 用TouchID/FaceID验证
    // LAPolicyDeviceOwnerAuthentication: 用TouchID/FaceID或密码验证, 默认是错误两次或锁定后, 弹出输入密码界面
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
        [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:description reply:^(BOOL success, NSError * _Nullable error) {
            
            if (success) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"TouchID/FaceID 验证成功");
                    block(SDAuthIDStateSuccess, error);
                });
            } else if(error){
                if ((iOS 11.0, *)) {
                    switch (error.code) {
                        case LAErrorAuthenticationFailed:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 验证失败");
                                block(SDAuthIDStateFail, error);
                            });
                            break;
                        }
                        case LAErrorUserCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被用户手动取消");
                                block(SDAuthIDStateUserCancel, error);
                            });
                        }
                            break;
                        case LAErrorUserFallback:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"用户不使用TouchID/FaceID,选择手动输入密码");
                                block(SDAuthIDStateInputPassword, error);
                            });
                        }
                            break;
                        case LAErrorSystemCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                                block(SDAuthIDStateSystemCancel, error);
                            });
                        }
                            break;
                        case LAErrorPasscodeNotSet:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无法启动,因为用户没有设置密码");
                                block(SDAuthIDStatePasswordNotSet, error);
                            });
                        }
                            break;
                        case LAErrorBiometryNotEnrolled:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无法启动,因为用户没有设置TouchID/FaceID");
                                block(SDAuthIDStateTouchIDNotSet, error);
                            });
                        }
                            break;
                        case LAErrorBiometryNotAvailable:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 无效");
                                block(SDAuthIDStateTouchIDNotAvailable, error);
                            });
                        }
                            break;
                        case LAErrorBiometryLockout:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID/FaceID 被锁定(连续多次验证TouchID/FaceID失败,系统需要用户手动输入密码)");
                                block(SDAuthIDStateTouchIDLockout, error);
                            });
                        }
                            break;
                        case LAErrorAppCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                                block(SDAuthIDStateAppCancel, error);
                            });
                        }
                            break;
                        case LAErrorInvalidContext:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                                block(SDAuthIDStateInvalidContext, error);
                            });
                        }
                            break;
                        default:
                            break;
                    }
                } else {
                    // iOS 11.0以下的版本只有 TouchID 认证
                    switch (error.code) {
                        case LAErrorAuthenticationFailed:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 验证失败");
                                block(SDAuthIDStateFail, error);
                            });
                            break;
                        }
                        case LAErrorUserCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被用户手动取消");
                                block(SDAuthIDStateUserCancel, error);
                            });
                        }
                            break;
                        case LAErrorUserFallback:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"用户不使用TouchID,选择手动输入密码");
                                block(SDAuthIDStateInputPassword, error);
                            });
                        }
                            break;
                        case LAErrorSystemCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                                block(SDAuthIDStateSystemCancel, error);
                            });
                        }
                            break;
                        case LAErrorPasscodeNotSet:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无法启动,因为用户没有设置密码");
                                block(SDAuthIDStatePasswordNotSet, error);
                            });
                        }
                            break;
                        case LAErrorTouchIDNotEnrolled:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无法启动,因为用户没有设置TouchID");
                                block(SDAuthIDStateTouchIDNotSet, error);
                            });
                        }
                            break;
                            //case :{
                        case LAErrorTouchIDNotAvailable:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 无效");
                                block(SDAuthIDStateTouchIDNotAvailable, error);
                            });
                        }
                            break;
                        case LAErrorTouchIDLockout:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)");
                                block(SDAuthIDStateTouchIDLockout, error);
                            });
                        }
                            break;
                        case LAErrorAppCancel:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                                block(SDAuthIDStateAppCancel, error);
                            });
                        }
                            break;
                        case LAErrorInvalidContext:{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                                block(SDAuthIDStateInvalidContext, error);
                            });
                        }
                            break;
                        default:
                            break;
                    }
                }
                
            }
        }];
        
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"当前设备不支持TouchID/FaceID");
            block(SDAuthIDStateNotSupport, error);
        });
    }
}


/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthTouchIDWithDescription:(NSString *)description
                localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                 block:(SDAuthIDStateBlock)block {
    [self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}

/**
 * 启动TouchID
 * @param description TouchID/FaceID显示的描述
 * @param localizedFallbackTitle 错误描述
 * @param block 回调状态的block
 */
- (void)showAuthFaceIDWithDescription:(NSString *)description
               localizedFallbackTitle:(NSString *)localizedFallbackTitle
                                block:(SDAuthIDStateBlock)block {
    [self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}

/**
 判断设备支持哪种认证方式 TouchID & FaceID
 */
- (SDAuthIDSupportType)canSupportBiometrics {
    LAContext *context = [[LAContext alloc] init];
    NSError *error;
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
        if (error != nil) {
            return SDAuthIDSupportTypeNone;
        }
        if ((iOS 11.0, *)) {
            return context.biometryType == LABiometryTypeTouchID ?  SDAuthIDSupportTypeTouchID:SDAuthIDSupportTypeFaceID ;
        }
    }
    return SDAuthIDSupportTypeNone;
}


具体使用方式如下;

需要在plist文件中添加 Privacy-Face ID Usage Description 属性
 <key>NSFaceIDUsageDescription</key>
 <string>允许设备访问Face ID</string>

 使用方式
 判断支持的类型
 SDAuthIDSupportType supportType = [[SDAuthID sharedInstance] canSupportBiometrics];
 SDAuthIDSupportType supportType = [[SDAuthID sharedInstance] canSupportBiometrics];
 
 NSString *description = @"";
 if(SDAuthIDSupportTypeFaceID == supportType){
     description = @"验证已有面容";
 } else if(SDAuthIDSupportTypeTouchID == supportType){
     description = @"通过Home键验证已有指纹";
 } else {
     description 

相关阅读

热门文章