Biometric authentication, Face ID doesn't get triggered

When a user swipes up to see the app switcher, I put a blocking view over my app so the data inside cannot be seen if you flick through the app switcher. I do this by checking if the scenePhase goes from .active to .inactive.

If the app goes into the background, scenePhase == .background so I trigger something that would force the user to authenticate with Face ID/Touch ID when the app is next brought to the foreground or launched.

However, this doesn't seem to work. The biometrics authentication is executed, but it just lets the user in without showing the Face ID animation. I put my finger over the sensors so it couldn't possibly be authenticating, but it just lets them in.

Here's a quick set of logs:

scenePhase == .inactive - User showed app switcher
scenePhase == .background - User swiped up fully, went to Home Screen
scenePhase == .inactive - User has tapped the app icon
scenePhase == .active - App is now active
authenticate() - Method called
authenticate(), authenticateViaBiometrics() == true - User is going to be authenticated via Face ID
// Face ID did not appear!
success = true - Result of calling `context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics` means user was authenticated successfully
error = nil - No error in the authentication policy
authenticate(), success - Method finished, user was authenticated

Here's the code:

print("authenticate(), authenticateViaBiometrics() == true - User is going to be authenticated via Face ID")
			var error: NSError?
			guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
				// Handle permission denied or error
				print("authenticate(), no permission, or error")
				authenticated = false
				defaultsUpdateAuthenticated(false)
				defaultsUpdateAuthenticateViaBiometrics(false)
				return
			}

			context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Authenticate with biometrics") { (success, error) in
				DispatchQueue.main.async {
					print("success = \(success)")
					print("error = \(String(describing: error?.localizedDescription))")
					if(success) {
						print("authenticate(), success")
						authenticated = true

					} else {
						print("authenticate(), failure")
						authenticated = false
					}
				}
			}

This happens with or without the DispatchQueue... call.

Answered by darkpaw in 801501022

I've figured it out. I was using a global context variable, but it seems to work only if I create a new variable every time I want to use the policy.

Doesn't make sense to me, but this doesn't work:

let context = LAContext()

func authenticate() {
  context.evaluatePolicy...
}

While this does:

func authenticate() {
  let context = LAContext()  // <-- Moved inside the function
  context.evaluatePolicy...
}

Any ideas, anyone?

Accepted Answer

I've figured it out. I was using a global context variable, but it seems to work only if I create a new variable every time I want to use the policy.

Doesn't make sense to me, but this doesn't work:

let context = LAContext()

func authenticate() {
  context.evaluatePolicy...
}

While this does:

func authenticate() {
  let context = LAContext()  // <-- Moved inside the function
  context.evaluatePolicy...
}
Biometric authentication, Face ID doesn't get triggered
 
 
Q