LAContext has method to check if device can evaluate touch ID and gives error message. Problem is that same error message "LAErrorPasscodeNotSet" is given by system in two cases:
1) If user has Touch ID, but turned it off in settings (iPhone 5s with iOS8)
2) If device doesn't have Touch ID (iPad with iOS8)
Q: How to check if device supports Touch ID, but haven't turned it on in settings?
Update:
Had created ticket to Apple regarding this bug (ID# 18364575) and received answer:
"Engineering has determined that this issue behaves as intended based on the following information:
If passcode is not set, you will not be able to detect Touch ID presence. Once the passcode is set, canEvaluatePolicy will eventually return LAErrorTouchIDNotAvailable or LAErrorTouchIdNotEnrolled and you will be able to detect Touch ID presence/state.
If users have disabled passcode on phone with Touch ID, they knew that they will not be able to use Touch ID, so the apps don't need to detect Touch ID presence or promote Touch ID based features. "
Tap Settings > Touch ID & Passcode, then enter your passcode. Tap Add a Fingerprint and hold your device as you normally would when touching the Touch ID sensor. Touch the Touch ID sensor with your finger—but don't press—so the device can begin recognizing your fingerprint.
I have updated answer. can we detect whether device supports Face ID or touch ID using only simulator ? Yes, You can test this using simulator. Select Simulator -> Hardware -> Touch ID -> Cases This will provide support for both based on simulator.
With the launch of the 2020 iPad Air, Apple put the Touch ID sensor in the top button, which increased speculation that the iPhone 13 could do the same. In spite of this development, the iPhone 13 does not have a Touch ID power button.
Maybe you could write your own method to check which device are you running on, because if returned error is the same, it would be hard to figure out exactly if Touch ID is supported. I would go with something like this:
int sysctlbyname(const char *, void *, size_t *, void *, size_t);
- (NSString *)getSysInfoByName:(char *)typeSpecifier
{
size_t size;
sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
char *answer = malloc(size);
sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];
free(answer);
return results;
}
- (NSString *)modelIdentifier
{
return [self getSysInfoByName:"hw.machine"];
}
After having the model identifier, I would just check if model identifier equals is one of the models that support Touch ID:
- (BOOL)hasTouchID
{
NSArray *touchIDModels = @[ @"iPhone6,1", @"iPhone6,2", @"iPhone7,1", @"iPhone7,2", @"iPad5,3", @"iPad5,4", @"iPad4,7", @"iPad4,8", @"iPad4,9" ];
NSString *model = [self modelIdentifier];
return [touchIDModels containsObject:model];
}
The array contains all model ID's which support Touch ID, which are:
The only downside of this method is that once new devices are released with Touch ID, the model array will have to be updated manually.
In Swift 3
fileprivate func deviceSupportsTouchId(success: @escaping () -> (), failure: @escaping (NSError) -> ()) {
let context = LAContext()
var authError: NSError?
let touchIdSetOnDevice = context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &authError)
if touchIdSetOnDevice {
DispatchQueue.main.async {
success()
}
}
else {
DispatchQueue.main.async {
failure(error!)
}
}
}
deviceSupportsTouchId() return Success if the device has touch Id capability.
If not then, function will return error, giving you the following error code if touchIDNotEnrolled is not set yet.
LAError.Code.touchIDNotEnrolled.rawValue
You can handle it using this value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With