FaceID

前言

指纹识别(TouchID),面容识别(FaceID)在iPhone中是频繁使用的,随时随地都在关闭手机,解锁手机。很多应用为了提高安全和便捷性也会提供相应的保护功能,尤其是涉及到金钱方面的应用,如各银行App、支付宝等。2017年做了一个应用,涉及到对应的功能,需要在退回到Home页面后再进入时弹出保护屏,支持指纹/面容解锁、手势解锁。当时在github上找一个比较方便的三方库,但是始终没有找到合适的,虽说功能不复杂,于是自己简单写了一版。

iOS中使用LocalAuthentication实现指纹识别/面容识别,为了方便,在下文中使用LA代替,LA也是此次更新代码的主要命名。由之前的TouchIDManager改为LAManager,避免过于片面。由于2018年随意取的名字且发布到了pods,此次更新并没有更新工程目录名(认为TouchIDManager)和pod名(为KJTouchIdManager)。

LA流程

已面容识别为例,指纹识别在失败尝试次数上要少一些,但整体流程是一致的

认证流程参考的是支付宝登录流程,大致流程如下(需在支付宝设置中开启LA登录):

  1. 登录时弹出面容识别认证框,如果识别成功,则直接进去支付宝首页
  2. 第一次认证失败,弹出未能识别,提示再次尝试。面容解锁点击再次尝试你面容ID进行识别
  3. 第二次认证失败,弹出提示框,可选重新登录支付宝和取消
  4. 点击取消,可再次点击锁屏页中的面容ID解锁唤起面容解锁
  5. 此时会重复依次走1,2,3,4步骤,也是还有两次认证的机会
  6. 如果点击取消后再次唤起面容识别,还是失败的话,会提示无法使用面容ID,此时已到达最大的尝试次数(5次)
  7. 再次点击取消后再唤起面容识别,此时会唤起系统密码认证框,输入密码成功解锁后,则可以再次使用面容解锁,相当于重置,恢复最大尝试次数5次
  8. 如果期间任何一次弹出重新登录按钮,点击重新登录按钮,则进行支付宝的其他登录方式,如刷脸登录、手机、邮箱登录等

效果图

FaceID

TouchID

关键点与鉴权方式选择

想要达到和支付宝一致的认证流程,首先需要知道LA的认证方式LAPolicy

指纹识别是从iOS8开始在iPhone5S系列上投入使用的,而面容识别是从iOS11开始在iPhoneX系列上使用的。LAPolicy分为deviceOwnerAuthenticationWithBiometricsdeviceOwnerAuthentication两种认证方式,他们的大致区别如下:

deviceOwnerAuthenticationWithBiometrics,生物识别(iOS 8+),错误最大次数(5次)后TouchID/FaceID会被锁住,期间会弹三次框,点取消后可重新进行解锁尝试,锁住后需要到设置里面去解锁才能重新认证。

deviceOwnerAuthentication,生物识别+密码认证(iOS 9+),指纹识别失败三次后会弹出系统密码验证,不输入密码点取消还有两次指纹识别,如果都失败TouchID被锁住,接下来都是通过系统密码进行验证;面容识别失败五次后会被锁住,之后的每次调用都会弹出系统密码进行验证。

鉴权方式选择:使用生物识别deviceOwnerAuthenticationWithBiometrics进行认证,当达到最大错误次数被锁定后,通过在错误回调中使用生物识别+密码认证deviceOwnerAuthentication的方式立马唤起系统密码进行解锁重置

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
/// 认证流程统一使用生物识别deviceOwnerAuthenticationWithBiometrics
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: localizedReason, reply: { (success, evaluateError) in
DispatchQueue.main.async {
if success {
self.resultDelegate?.handleLAResult(result: .success)
} else {
if let error = evaluateError as NSError? {
self.LAErrorHandle(errorCode: error.code, context: context)
}
}
}
})

只使用deviceOwnerAuthentication唤起系统密码框,达到解锁的目的

1
2
3
4
5
6
// 面容识别错误达到一定次数被锁定;换用deviceOwnerAuthentication「生物识别+密码认证」可立马触发系统密码框解锁【关键处理】
if errorCode == LAError.biometryLockout.rawValue { // 或者touchIDLockout (iOS9)
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: localizedReason, reply: { (success, error) in

})
}

LAManager使用

cocoapods

add KJTouchIdManager to your Podfile 在Podfile中加入(pod名称和实际代码类名称不符,是一开始没有想好如何命名,见谅[Lol])

1
pod 'KJTouchIdManager'

run pod install 运行安装命令:

1
pod install

手动导入

Drop TouchIdManager fold to your project 将TouchIdManager文件夹拖到你的工程目录(文件夹名称和实际代码类名称不符,是一开始没有想好如何命名,见谅[Lol])

代码

  1. declare an instance 声明一个实例
1
var laManager = LAManager()
  1. do some config 进行配置,设置认证结果代理,弹框标题等
1
2
3
4
5
6
// 设置代理,处理认证结果回调
laManager.resultDelegate = self
// 解锁失败后用户操作按钮的文字,默认为”输入密码“
laManager.localizedFallbackTitle = "使用密码登录应用"
// 解锁失败后的提示文字
laManager.localizedReason = "面容ID短时间内失败多次,您可以再次尝试或使用密码登录"
  1. implement protocol LAHandleable, handle result 实现认证结果代理,处理成功或失败操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// 遵循认证结果协议代理
/// 结果枚举详见LAResult
extension LockViewController: LAHandleable {

func handleLAResult(result: LAResult) {
switch result {
case .success:
dismiss(animated: true, completion: nil)
case .userFallback:
print("跳转到登录页,使用密码登录")
case .biometryNotEnrolled
print("您没有设置面容ID")
case ...
default: ()
}
}
}
  1. optional method 可选(判断TouchID/FaceID是否可用)
1
2
// 判断指纹/面容是否可用,如果不可用可直接跳过认证逻辑或者不显示相关认证按钮等信息
let isAvaliable = laManager.isAvaliable()

GitHub地址

具体使用可参考github源码和demo,传送门