Ios FaceID应回退到密码,但不返回

Ios FaceID应回退到密码,但不返回,ios,swift,touch-id,face-id,localauthentication,Ios,Swift,Touch Id,Face Id,Localauthentication,我继承了一个代码库,下面的类提供了对Face/Touch ID的支持 预期的行为是用户在脸/触摸ID成功时登录。这很有效 但是,如果用户未能通过Face ID并选择输入其密码,则在调用完成处理程序后,他们将被注销。我相信选择使用密码会触发 else { self.authState = .unauthenticated completion(.unauthenticated) } 如何触发密码提示?我是否应该使用LAPolicy.deviceOwnerAuthentication创建第二个

我继承了一个代码库,下面的类提供了对Face/Touch ID的支持

预期的行为是用户在脸/触摸ID成功时登录。这很有效

但是,如果用户未能通过Face ID并选择输入其密码,则在调用完成处理程序后,他们将被注销。我相信选择使用密码会触发

else {
 self.authState = .unauthenticated
 completion(.unauthenticated)
}
如何触发密码提示?我是否应该使用
LAPolicy.deviceOwnerAuthentication
创建第二个策略并对其进行评估

import LocalAuthentication

public enum AuthenticationState {
    case unknown
    case authenticated
    case unauthenticated

    public func isAuthenticated() -> Bool {
        return self == .authenticated
    }
}

public protocol TouchIDAuthenticatorType {
    var authState: AuthenticationState { get }
    func authenticate(reason: String, completion: @escaping (AuthenticationState) -> Void) -> Void
    func removeAuthentication() -> Void
}

public protocol LAContextType: class {
    func canEvaluatePolicy(_ policy: LAPolicy, error: NSErrorPointer) -> Bool
    func evaluatePolicy(_ policy: LAPolicy, localizedReason: String, reply: @escaping (Bool, Error?) -> Void)
}

public class TouchIDAuthenticator: TouchIDAuthenticatorType {
    public var authState: AuthenticationState = .unknown

    private var context: LAContextType
    private var policy = LAPolicy.deviceOwnerAuthenticationWithBiometrics

    public init(context: LAContextType = LAContext()) {
        self.context = context
    }

    public func authenticate(reason: String, completion: @escaping (AuthenticationState) -> Void) -> Void {
        var error: NSError?

        if context.canEvaluatePolicy(policy, error: &error) {
            context.evaluatePolicy(policy, localizedReason: reason) { (success, error) in
                DispatchQueue.main.async {
                    if success {
                        self.authState = .authenticated
                        completion(.authenticated)
                    } else {
                        self.authState = .unauthenticated
                        completion(.unauthenticated)
                    }
                }
            }
        } else {
            authState = .authenticated
            completion(.authenticated)
        }
    }

    public func removeAuthentication() -> Void {
        authState = .unknown
        context = LAContext() // reset the context
    }
}

extension LAContext: LAContextType { }

我要指出的是,在模拟器上,这似乎能像预期的那样工作,但在设备上它不能工作,我注销了。

你必须使用
.deviceOwnerAuthentication
,而不是要求生物识别。如果FaceID可用,它将强制尝试以任何一种方式使用它

如果您尝试了足够多的时间,那么您将得到另一个对话框“取消”或回退到“使用密码”。 选择回退将显示密码屏幕

但是,如果指定了
.deviceOwnerAuthenticationWithBiometrics
,您将获得相同的回退选项。我没有得到这个对话,而是希望收到一个错误
LAError.code.biometrillockout
。但相反,我得到了这个备用选项对话。但那没关系

但是,如果我点击回退选项“使用密码”,它将不会显示密码警报。相反,它会失败,出现
LAError.code.userFallback错误

如果您在没有生物识别的情况下使用策略,您将无法获取并能够捕获.userFallback错误

总而言之:

  • 如果您要求
    设备拥有者使用生物识别技术进行身份验证
    策略,则您必须自己处理回退
  • 如果您仅要求
    deviceOwnerAuthentication
    ,则将使用生物特征识别技术(如果可用且经授权),否则,如果生物特征识别技术不可用,它将自动返回密码,或者如果生物特征识别尝试失败,它将为您提供自动输入密码的回退选项

  • 您是否尝试过在中放置断点并检查错误是什么?您将确切地知道代码的哪一部分至少正在执行,因为您听起来并不是100%确定。如果用户未启用
    FaceID/TouchID
    ,那么您应该只显示默认的身份验证流。在设备上,检查是否已启用
    FaceID/TouchID
    。它可以在模拟器上工作,因为您可以简单地注册和匹配/取消匹配。也许这一个可以帮助您检查并尝试
    策略
    必须更改为
    LAPolicy.deviceOwnerAuthentication
    ,以便返回密码验证。