由于接下来的项目需要接触到触控ID以及面容ID支付,发现API调用简单但是支付宝微信等还做了新旧录用信息对比evaluatedPolicyDomainState的逻辑(或许不是这么简单),so简单封装一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
////////// .h file
#import <Foundation/Foundation.h>
@interface LocalAuthManager : NSObject
+ (instancetype)sharedInstance;
- (BOOL)isSupportTouchID;
- (BOOL)isSupportFaceID;
- (void)showAuthIDWithDescribe:(NSString *)describe block:(void (BOOL success, NSError * _Nullable error))block;
- (void)setCurrentUserAuthDataWithIdentity:(NSString *)identity;
- (NSData *)currentUserAuthData:(NSString *)identity;
@end
////////.m file
#import "LocalAuthManager.h"
#import <LocalAuthentication/LocalAuthentication.h>
#import "SAMKeychain.h"
#import <UIKit/UIKit.h>

#define iPhoneX (UIScreen.mainScreen.bounds.size.width >= 375.f && UIScreen.mainScreen.bounds.size.height >= 812.f)
#define Auth_ID_DATA_SERVICE @"Auth_ID_DATA_SERVICE"

@implementation LocalAuthManager

static LocalAuthManager *_instance;

#pragma mark - 单例
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_instance == nil) {
_instance = [[super allocWithZone:NULL] init];
}
});
return _instance;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
-(id)copyWithZone:(NSZone *)zone
{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
return _instance;
}

#pragma mark - 判断是否支持触控ID
- (BOOL)isSupportTouchID{
LAContext *laContext = [[LAContext alloc] init];
NSError *error = nil;
//LAPolicyDeviceOwnerAuthenticationWithBiometrics判断TouchID和FaceID
[laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
if (error.code == LAErrorTouchIDNotAvailable)
return NO;
return YES;
}
#pragma mark - 判断是否支持面容ID
- (BOOL)isSupportFaceID{
if (iPhoneX && [UIDevice currentDevice].systemVersion.doubleValue >= 11.0)
return YES;
return NO;
}
#pragma mark - 显示验证
- (void)showAuthIDWithDescribe:(NSString *)describe block:(void (BOOL success, NSError * _Nullable error))block{
if (!describe) {
if (iPhoneX) {
describe = @"验证已有面容";
}else{
describe = @"通过Home键验证已有指纹";
}
}

if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"系统版本低于8.0");
});
return;
}

LAContext *context = [[LAContext alloc] init];
NSError *error;
context.localizedFallbackTitle = @"输入密码";
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:describe reply:^(BOOL success, NSError * _Nullable error) {
block(success,error);
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"当前设备不支持TouchID/FaceID");
});
}
}
#pragma mark - 根据当前用户标识的保存TouchID/FaceID信息
- (void)setCurrentUserAuthDataWithIdentity:(NSString *)identity {
LAContext *context = [[LAContext alloc] init];
NSError *error;
if (![context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
NSLog(@"save authe error:%@",error);
return;
}
if (identity && context.evaluatedPolicyDomainState) {
[SAMKeychain setPasswordData:context.evaluatedPolicyDomainState forService:Auth_ID_DATA_SERVICE account:identity error:&error];
}
}
#pragma mark - 根据当前用户标识的获取TouchID/FaceID信息
- (NSData *)currentUserAuthData:(NSString *)identity {
return [SAMKeychain passwordDataForService:Auth_ID_DATA_SERVICE account:identity];
}

@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef NS_ENUM(NSInteger, LAError)
{
LAErrorAuthenticationFailed, // 验证信息出错
LAErrorUserCancel // 用户取消了验证
LAErrorUserFallback // 用户点击了手动输入密码的按钮
LAErrorSystemCancel // 被系统取消,就是说你现在进入别的应用了,不在刚刚那个页面,所以没法验证
LAErrorPasscodeNotSet // 用户没有设置文本密码
LAErrorTouchIDNotAvailable // 用户设备不支持TouchID
LAErrorTouchIDNotEnrolled // 用户没有设置手指指纹
LAErrorTouchIDLockout // 用户错误次数被锁了
LAErrorAppCancel // 在验证中被其他app中断
LAErrorInvalidContext // 请求验证出错
LAErrorBiometryNotAvailable // 多次验证(T&F二者)失败被锁定
LAErrorBiometryNotEnrolled // 用户没有设置触控ID、面容ID
LAErrorBiometryLockout // 触控ID、面容ID被锁了
LAErrorNotInteractive // 验证失败,使用了禁止UI
} NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);

thanks for your reading~