Is it possible to cancel the TouchID alert dialog programmatically after the LAContext.evaluatePolicy
call? If yes: how?
Not every API Apple publishes makes it into the documentation on developer.apple.com (or in Xcode's docs viewer). The API diffs list public APIs, so anything you see there is in the header files (see LocalAuthentication/LAContext.h
) and the Swift interfaces generated from those headers. And anything that's in the headers is a public API, so you're free to call it.
Sometimes (but not always) the undocumented APIs have decent header comments explaining how to use them... thankfully LAContext.invalidate()
is one of these:
/// Invalidates the context.
///
/// @discussion The context is invalidated automatically when it is (auto)released. This method
/// allows invalidating it manually while it is still in scope.
///
/// Invalidation terminates any existing policy evaluation and the respective call will
/// fail with LAErrorAppCancel. After the context has been invalidated, it can not be
/// used for policy evaluation and an attempt to do so will fail with LAErrorInvalidContext.
///
/// Invalidating a context that has been already invalidated has no effect.
@available(iOS 9.0, *)
public func invalidate()
Indeed, it looks like calling invalidate()
while the Touch ID alert is visible should dismiss it. (I haven't tried myself.)
iOS 11 update: Note that on devices with Face ID instead of Touch ID, the alert/HUD-like UI that appears when you call LAContext.evaluatePolicy
doesn’t require or allow interaction, and dismisses itself upon successful authentication. Theoretically, the invalidate
call still dismisses it (or the followup, actually-interactive alert that appears if Face ID doesn’t identify the user).
But it might not be wise to assume that on all possible devices and authentication methods you’ll always have enough time to cancel LAContext
authentication after asking for it.
In my case, I find out why it not working because the LAContext instance I try to invalidate() is not the same instance who I call evaluatePolicy().
So You need to make sure that all ViewControllers shared the same instance. swift 4
public class MyBiometryUtility: NSObject {
static private var sharedBiometry: MyBiometryUtility? = nil
var context: LAContext = LAContext()
@objc public static func sharedInstance() -> MyBiometryUtility{
if let sharedBiometry = sharedBiometry {
return sharedBiometry;
} else{
sharedBiometry = MyBiometryUtility()
return sharedBiometry!
}
}
public func tryBiometryAuth() { ... }
public func closeBiometryAuth() {... }
In SomeViewController.swift
func buttonTapped(sender: Any){
// show dialog.
MyBiometryUtility.sharedInstance().tryBiometryAuth()
}
func timerCountDown(){
// close dialog.
if tooLong() {
MyBiometryUtility.sharedInstance().closeBiometryAuth()
}
}