最近做项目版本更新有个需求是 3DTouch解锁功能, 由此原因接触 Apple的指纹解锁功能, 基本功能原先已经实现好了,发现了一个 Bug然后来优化一下,先扯会儿等下我会附上源代码, 其实在指纹解锁功能上 Apple已经帮我们封装好了, 我们需要写的代码其实并不多。
想更详细了解的可以直接参考Apple文档:https://developer.apple.com/documentation/localauthentication。不过我个人更推荐的学习方法是在学习一个新知识点时,最好先参考一篇觉得写得不错,自己更容易理解的Blog看看作者的理解分析,以及有源代码 Dome附上更佳!!! 因为对于一个新的知识点类库, 会有很多我们没接触过的类,以及一些API的调用等。我们直接一头雾水的去看Apple文档可能效果不会最佳。
好了上面扯的一大堆废话,现在该步入正题了。
我会直接参考着 Apple文档介绍做指纹解锁功能用到的类以及 API的调用等。
一.LAContext
顾名思义此类是关于锁认证凭证的一个上下文类。我们我们直接从此类入手, 引用官方文档概念说明:认证上下文用于评估认证策略,允许应用程序请求用户使用诸如使用 Touch ID注册的指纹等个人信息进行身份验证。 其是管理认证凭证的一个核心类 文档说明中还有一条重要的信息SDK要求: iOS 8.0以上版本、只有iOS 8.0以上版本才可以正常使用指纹解锁功能! 然后我们来看一下此类包含的属性以及API。从 Xcode进入官方声明的的LAContext文件可见其内容并不多,只有290行代码。分别罗列其公共的属性:
@property (nonatomic, nullable, copy) NSString localizedFallbackTitle;//我们可以先看一下文档上的注释, 其表示的是指纹解锁弹框的回退按钮标题,/// @discussion Allows fallback button title customization. A default title "Enter Password" is used whenthis property is left nil. If set to empty string, the button will be hidden.从文档注释上我们还可以看出这个按钮标题默认是“输入密码”,如果我们将此属性设置为nil 此按钮会隐藏掉。
@property (nonatomic, nullable, copy) NSString localizedCancelTitle 取消按钮标题。 默认值是 Cancel 、 我们可以自定义设置 按钮Title 也可以设置为 nil 或者其他字符串。
@property (nonatomic, nullable) NSNumber maxBiometryFailures NS_DEPRECATED_IOS(8_3, 9_0) __WATCHOS_UNAVAILABLE __TVOS_UNAVAILABLE; //// 此属性是设置允许验证失败最大次数、 默认如果不设置的话 是3次之后验证失败、 文档注释有个警告说明 是 /// @warning Please note that setting this property with high values does not prevent biometry lockout after 5 设置了属性之后即时认证失败次数超过了5次、也会直接认证失败。 在Apple文档上 看到此属性已经被标记为 弃用 ,所以我们最好直接使用默认的 3次即可!
touchIDAuthenticationAllowableReuseDuration
允许使用Touch ID身份验证的持续时间。
继续到相关API:
- canEvaluatePolicy:error:
预先验证身份验证策略,以查看身份验证是否可以成功。 // 我们可以直接使用此方法来判断此设备是否支持使用指纹解锁。返回值是个BOOL
- evaluatePolicy:localizedReason:reply:
//核心方法。直接使用 ALContext实例调用此方法,直接弹出指纹认证框。详细解释一下里面的三个参数
@param->policy 其是一个枚举。具体看https://developer.apple.com/documentation/localauthentication/lapolicy?language=objc 介绍、 我们直接使用枚举第一个参数。
@param->localizedReason 类型是NSString、 我们可以提供一段字符串,其会展示在弹框中间。如"Wechat请你您验证指纹"等、
@param->reply 此参数是一个 返回值为空,第一个参数是BOOL 表示验证执行结果、第二个参数是NSError 表示执行错误原因 的回调block。 我们可以在调用此方法时把具体回调执行步骤 根据 参数 执行我们想要执行的操作。然后回调失败具体是一个 枚举 LAError 我们可以参考https://developer.apple.com/documentation/localauthentication/laerror?language=objc 里面有不同的失败原因。
- invalidate
使验证上下文无效。// 在验证期间调用此方法 相当于是此次验证失败。 失败的原因类似 系统取消等。
还有剩下几个API 由于开发指纹解锁 仅需要 用到这两个即可!写的太多感觉有点啰嗦。 所以暂时先不对其介绍。目前我们只要搞懂这几个属性和API即可轻松完成指纹解锁的功能。因为具体的弹框指纹验证等主要的功能 Apple已经帮我们封装好了。 只要我们调用 刚刚介绍的第二个API 即可 一步完成指纹 验证。 是不是超级超级简单!!!!!* 讲到这里大家应该对指纹解锁有了一个大概的了解了**。在此附上一段简短的实现代码供大家参考。
指纹解锁实现参考:
LAContext context = [[LAContext alloc] init];
NSError error = nil;
BOOL canUse = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
if(canUse) {
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"Jersey请您验证指纹"reply:^(BOOL success, NSError error) {
NSLog(@"evaluatePolicy Biometrics %@",error);
if (success) {
//注意我们在执行回调的时候必须使用异步、否则会卡顿。影响体验*
dispatch_async(dispatch_get_main_queue(), ^{
reply(YES, error);
});
}
else {
switch (error.code) {
case LAErrorTouchIDLockout:
{
NSLog(@"验证失败,由于认证次数超过指定次数。账户可能会被锁定");
// 我再这里调用封装好的方法,让用户先去验证一次手机密码,成功之后才能继续使用指纹验证。
}
break;
case LAErrorUserCancel:
{
NSLog(@"验证失败,用户点击取消");
}
break;
default:
{
dispatch_async(dispatch_get_main_queue(), ^{
reply(NO, [NSError errorWithDomain:@"Touch ID Failed." code:TouchIDErrorFailed userInfo:nil]);
});
}
break;
}
}
}];
}
只需调用此方法即可实现弹框提示用户进行指纹验证。感谢Apple给力的封装! 但是不要高兴的太早,目前我正在使用此API出现的问题就是,当用户快速点击两次指纹验证按钮时, 此API会直接调用两次, 然后直接出现的问题就是第一次弹框出现后消失,然后继续弹出一个验证的框。 然后我在API的错误回调里面执行了一个弹框提示的方法、此时问题就出来了。不仅弹两次框,还提示一个验证失败的指示器。看着有点不舒服。但是由于此功能Apple已经封装完好, 并没有把弹出的框属性直接暴露出来、 我目前还找不到合适的办法去检测此ALContext是否正在处于验证状态。 所以只能想了其他方法先把目前遇到的问题解决了。
方法一:延迟当前按钮相应弹框事件的时间。 这样一来不管用户点击多少次最终只会执行一次点击的事件,我们可以设一个延长时间,每次点击这个按钮的时候会把上次点击发送的事件取消掉。直到我们设置的延时后才会去执行一次这个事件 附上代码
- (void)clickfingerprintBtnAction:(UIButton *)btn{
// 在0.2秒时间间隔内多次点击只响应一次点击事件, todoSomething就是我们具体要实现的方法
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(todoSomething:) object:btn];
[self performSelector:@selector(todoSomething:) withObject:btn afterDelay:0.2f];
}
-(void)todoSomething:(UIButton *)btn{
//这里直接写我们具体的指纹认证实现即可
}
此方法的也可以有效的防止连续弹框、因为不管点击多少次最终只会执行一次弹框认证的事件。但是缺点就是每次点击完要延迟个0.2S才会执行指纹弹框认证。
方法二: 在类中创建一个标识符、用来表示当前是否正在验证。 我们在调用弹框操作前 根据此属性去判断弹框是否存在。 如存在则不去执行直接 return即可。 然后我们在每次执行方法前 将 此属性 改为 YES、 在方法的回调 将 此属性 改为 NO即可。
希望此篇文章对您有所帮助,如有不对的地方,希望大家能留言指出纠正。谢谢!!!
学习的路上, 与君共勉!!!
在文章结尾给大家附上一篇已经写好的Dome供大家继续参考 ------> https://github.com/ClearLoveLee/LM_TouchID