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) {
SDAuthIDSupportTypeTouchID = 1,
SDAuthIDSupportTypeFaceID,
SDAuthIDSupportTypeNone,
};
typedef NS_ENUM(NSUInteger, SDAuthIDState){
SDAuthIDStateNotSupport = 0,
SDAuthIDStateSuccess = 1,
SDAuthIDStateFail = 2,
SDAuthIDStateUserCancel = 3,
SDAuthIDStateInputPassword = 4,
SDAuthIDStateSystemCancel = 5,
SDAuthIDStatePasswordNotSet = 6,
SDAuthIDStateTouchIDNotSet = 7,
SDAuthIDStateTouchIDNotAvailable = 8,
SDAuthIDStateTouchIDLockout = 9,
SDAuthIDStateAppCancel = 10,
SDAuthIDStateInvalidContext = 11,
SDAuthIDStateVersionNotSupport = 12
};
typedef void (^SDAuthIDStateBlock)(SDAuthIDState state, NSError *error);
@interface SDAuthID : NSObject
+ (instancetype)sharedInstance;
- (SDAuthIDSupportType)canSupportBiometrics;
- (void)showAuthIDWithDescription:(NSString *)description
localizedFallbackTitle:(NSString *)localizedFallbackTitle
block:(SDAuthIDStateBlock)block;
- (void)showAuthTouchIDWithDescription:(NSString *)description
localizedFallbackTitle:(NSString *)localizedFallbackTitle
block:(SDAuthIDStateBlock)block;
- (void)showAuthFaceIDWithDescription:(NSString *)description
localizedFallbackTitle:(NSString *)localizedFallbackTitle
block:(SDAuthIDStateBlock)block;
@end
实现的代码
SDAuthID.m
#import "SDAuthID.h"
@implementation SDAuthID
+ (instancetype)sharedInstance {
static SDAuthID *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[SDAuthID alloc] init];
});
return instance;
}
- (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;
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 (@available(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 {
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 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);
});
}
}
- (void)showAuthTouchIDWithDescription:(NSString *)description
localizedFallbackTitle:(NSString *)localizedFallbackTitle
block:(SDAuthIDStateBlock)block {
[self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}
- (void)showAuthFaceIDWithDescription:(NSString *)description
localizedFallbackTitle:(NSString *)localizedFallbackTitle
block:(SDAuthIDStateBlock)block {
[self showAuthIDWithDescription:description localizedFallbackTitle:localizedFallbackTitle block:block];
}
- (SDAuthIDSupportType)canSupportBiometrics {
LAContext *context = [[LAContext alloc] init];
NSError *error;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
if (error != nil) {
return SDAuthIDSupportTypeNone;
}
if (@available(iOS 11.0, *)) {
return context.biometryType == LABiometryTypeTouchID ? SDAuthIDSupportTypeTouchID:SDAuthIDSupportTypeFaceID ;
}
}
return SDAuthIDSupportTypeNone;
}
@end
具体使用方式如下;
需要在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