If your app uses biometrics, you’ll likely want to know whether TouchID or FaceID is available on a user’s iOS device. For example, you may want to show a button on the login screen that has the appropriate icon for whichever biometrics capability the user has. Or you may want to set the correct text in your app settings so it shows “FaceID” or “TouchID”.
We can determine which biometric option is available by checking the biometricsType
property on an instance of the LAContext
class. The possible values for biometricsType
are .faceID
, .touchID
and .none
. As an aside, the purpose of the LAContext
class is to allow the developer verify what policies can be used for authentication (e.g. biometrics, passcode or Apple Watch), as well as interact with the Secure Enclave on the device to verify the user’s identity.
The first step in determining what biometrics type is available is to call the canEvaluatePolicy(_:error:)
method on a context that’s been initialized. We pass in .deviceOwnerAuthenticationWithBiometrics
, and we’ll know right away whether any biometrics are available to be used. An important note here: if you try checking the biometricsType
property on the context but haven’t called this method first, the property’s value will always be .none
.
After calling canEvaluatePolicy(_:error:)
, we access the biometricsType
property and can make use of its value.
func getBiometricsType() -> LABiometryType {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
return .none
}
return context.biometryType
}
func getBiometricsName() -> String {
switch getBiometricsType() {
case .faceID:
return "FaceID"
case .touchID:
return "TouchID"
case .none:
return "Biometrics Unavailable"
@unknown default:
return "Unknown Biometrics Type"
}
}
myLabel.text = getBiometricsName() // "TouchID" when on an iPhone 8
When the Device Isn’t Enrolled
A caveat in the above is that the user must be enrolled in TouchID or FaceID in order for the corresponding value to be returned. In other words, if a user is on an iPhone 11, but hasn’t enrolled in FaceID in device settings, the biometryType
property will always return .none
. That value will also be returned if the user has enrolled in FaceID, but has denied permission for the app to use it.
For many apps, that may be fine, since you only want to display anything about biometrics if it’s available to use. Other apps may need to know what biometrics type a device has, whether enrolled or not. An example could be to show a FaceID or TouchID option in the app settings regardless of enrollment—but if they aren’t, provide a message that they need to do this in system settings.
This can be accomplished by passing in .deviceOwnerAuthentication
as the policy into canEvaluatePolicy(_:error:)
instead of .deviceOwnerAuthenticationWithBiometrics.
The value on biometryType
will then indicate at the device level what biometrics type is available. In that case, our function above would be:
func getBiometricsType() -> LABiometryType {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
return .none
}
return context.biometryType
}
Another option is simply to use DeviceKit. This is a lightweight library that will allow you to check hasBiometricSensor
, isFaceIDCapable
, or isTouchIDCapable
properties on the device.