LAContext canEvaluatePolicy and Swift 2 - ios

This is my code in Swift:
if (LAContext().canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics)) {
return true;
}
With Swift2 I changed my code to look like this:
if #available(iOS 8, *) {
if (LAContext().canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics)) {
return true;
}
}
But I get the following error:
Call can throw, but it is not marked with 'try' and the error is not handled
What Am I doing wrong?

You need to do something like this:
do {
try laContext.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics)
// Call evaluatePolicy here
} catch {
print("Cannot evaluate policy, error: \(error)")
}
All methods that returned a Bool and had an inout NSError? as the last parameter were automatically converted (Swift 2) to throw the error, so the parameter was removed. Also the Bool was redundant because it was equal to whether the inout NSError? is nil
EDIT: To get more information about the error use this within the catch:
switch LAError(rawValue: error.code)! {
case .AuthenticationFailed:
break
case .UserCancel:
break
case .UserFallback:
break
case .SystemCancel:
break
case .PasscodeNotSet:
break
case .TouchIDNotEnrolled:
break
default:
break
}
(You can look at all the possible errors by CMD clicking on LAError
EDIT: In XCode 7 beta 5/6 this method doesn't throw anymore, but takes an NSErrorPointer as the last parameter (as does NSURL's checkResourceIsReachableAndReturnError for reasons not known to me). You can however extend your LAContext to make a throwing method like before if you like:
extension LAContext {
func canEvaluatePolicyThrowing(policy: LAPolicy) throws {
var error : NSError?
canEvaluatePolicy(policy, error: &error)
if let error = error { throw error }
}
}

Try this code:
do {
try touchIDContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics)
//Comprobar la repuesta de esa autentificacion
touchIDContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: mensaje, reply: { (success, ErrorType) -> Void in
if success
{
// Autentificacion correcta
alert.title = "Genial!"
alert.message = "Te has autentificado correctamente"
// Mostramos este Alerview
self.presentViewController(alert, animated: true, completion: nil)
}
else
{
//AUTENTIFICACION FALLIDA
//PASAMOS VALORES AL ALERTVIEW
alert.title = "AUTENTIFICACION FALLIDA!!"
//OFRECEMOS MAS INFORMACION SOBRE EL FALLO DE AUTENTIFICAICON
switch ErrorType!.code {
case LAError.UserCancel.rawValue: alert.message = "Usuario Cancela"
case LAError.AuthenticationFailed.rawValue: alert.message = "Autentificacion Fallida!"
case LAError.PasscodeNotSet.rawValue: alert.message = "Password no configurado"
case LAError.SystemCancel.rawValue: alert.message = "Error de sistema"
case LAError.UserFallback.rawValue:alert.message = "Usuario selecciona contrasen"
default:alert.message = "Imposible Autentificarse"
}
//Mostramos el AlertView
self.presentViewController(alert, animated: true, completion: nil)
}
}) // cierre del clousure
} // cierre del do
catch {
print("Cannot evaluate policy, error: \(error)")
} // cierre del catch

For Swift 3, I do this:
context.evaluatePolicy(policy, localizedReason: ...) { (success: Bool, error: Error?) in
DispatchQueue.main.async {
if success {
...
} else if let error = error as? LAError {
switch error.code {
case LAError.authenticationFailed:
...
}
}
}
}

Related

How to check user are logged correctly in firebase swift app?

I have issue, even when i put wrong password, my app showing me info about Success login, but in reality im not. How to make work it properly?
Auth.auth().fetchSignInMethods(forEmail: userEmail, completion: {
(providers, error) in
if error != nil {
self.displayAlertMessage(alertTitle: "Unhandled error", alertMessage: "Undefined error #SignUpViewController_0001");
return;
} else if providers == nil {
self.displayAlertMessage(alertTitle: "Error", alertMessage: "This account is not exist.");
return;
}
})
// Login
Auth.auth().signIn(withEmail: userEmail, password: userPassword) { [weak self] authResult, error in
guard self != nil else {
self?.displayAlertMessage(alertTitle: "Alert", alertMessage: "Wrong password.");
return }
}
self.displayAlertMessage(alertTitle: "Success", alertMessage: "You are successfuly sign in.", dismiss: true);
// Return to initial view
Auth.auth().signIn() is asynchronous and returns immediately. The callback you pass will be invoked some time later with the results of the sign in. What your code is doing is immediately calling self.displayAlertMessage(alertTitle: "Success",...) before the sign in is complete. You should only expect sign in results inside the callback, not on the next line of code after you call signIn().
This function I wrote for my current application.
func loginButtonTapped() {
indicator.setupIndicatorView(view, containerColor: .white, indicatorColor: .CustomGreen())
view.alpha = 0.7
let email = mainView.userEmail
let password = mainView.userPassword
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if error == nil {
if Auth.auth().currentUser?.isEmailVerified == true {
self.view.alpha = 1.0
self.indicator.hideIndicatorView()
print("Logined")
} else {
Auth.auth().currentUser?.sendEmailVerification(completion: { (error) in
if error == nil {
self.view.alpha = 1.0
self.indicator.hideIndicatorView()
Alert.showAlert(title: "Warning", subtitle: "You have not activate your account yet. We have sent you an email to activate it.", leftView: UIImageView(image: #imageLiteral(resourceName: "isWarningIcon")), style: .warning)
} else {
self.view.alpha = 1.0
self.indicator.hideIndicatorView()
Alert.showAlert(title: "Error", subtitle: "Incorrect email.", leftView: UIImageView(image: #imageLiteral(resourceName: "isErrorIcon")), style: .danger)
}
})
}
} else {
self.view.alpha = 1.0
self.indicator.hideIndicatorView()
Alert.showAlert(title: "Error", subtitle: "Incorrect email or password.", leftView: UIImageView(assetIdentifier: AssetIdentifier.error)!, style: .danger)
}
}
}
As Doug mentioned in his answer, Firebase is asynchronous and data is only valid within the closure following the function call. It takes time for that data to become valid so any code outside the function call following the closure will be called before the code inside the closure.
So what that means for your code is
Auth.auth().signIn(withEmail: userEmail, password: userPassword) { [weak self] authResult, error in
//this code will execute *after* the code that displays success
}
//this code will execute *before* the code within the closure following the signIn
self.displayAlertMessage(alertTitle: "Success"
Here's some sample code that handles errors and provides the proper sequence for code flow.
Auth.auth().signIn(withEmail: user, password: pw, completion: { (auth, error) in
if let x = error {
let err = x as NSError
switch err.code {
case AuthErrorCode.wrongPassword.rawValue:
print("wrong password")
case AuthErrorCode.invalidEmail.rawValue:
print("invalued email")
case AuthErrorCode.accountExistsWithDifferentCredential.rawValue:
print("accountExistsWithDifferentCredential")
default:
print("unknown error: \(err.localizedDescription)")
}
} else {
if let _ = auth?.user {
print("authd") //user is auth'd proceed to next step
} else {
print("authentication failed - no auth'd user")
}
}
})

How to get a callback every time faceid/touchid authentication fails

We have a requirement where we have to block the user for 24 hours if Face ID or Touch ID fails for 5 consecutive time.
In Face ID, I am using the fallback to call authentication manager again, and after total of 6 attempts (2 in each call), I block the user in the fallback method itself.
In Touch ID, on third failure, I get a call back to Authentication failed. I call authentication manager again, and on 5th try, I get a call back to Lockout in which I can block the user.
Is there any way common in both Face ID and Touch ID where I can get a callback after every single individual failure so that I can block the user on 5th failure itself?
//MARK:- Check if user has valid biometry, if yes, validate, else, show error
fileprivate func biometricAuthentication(completion: #escaping ((Bool) -> ())){
// addBlurredBackground()
//Check if device have Biometric sensor
if biometryRetryCount == 2 {
authenticationContext.localizedFallbackTitle = "Ok"
} else {
authenticationContext.localizedFallbackTitle = "Retry"
}
let isValidSensor : Bool = authenticationContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
if isValidSensor {
//Device have BiometricSensor
authenticationContext.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: biometryRetryCount == 2 ? "You have been blocked from using the application for next 24 hours. Please come back later" : "Touch / Face ID authentication",
reply: { [unowned self] (success, error) -> Void in
if(success) {
// Touch or Face ID recognized
// self.removeBlurredBackground()
completion(true)
} else {
//If not recognized then
if let error = error {
let msgAndAction = self.errorMessage(errorCode: error._code)
if msgAndAction.0 != "" {
UIApplication.topViewController()?.showAlert(withTitle: "Error", andMessage: msgAndAction.0, andActions: msgAndAction.1)
}
}
completion(false)
}
})
} else {
let msgAndAction = self.errorMessage(errorCode: (error?._code)!)
if msgAndAction.0 != ""{
UIApplication.topViewController()?.showAlert(withTitle: "Error", andMessage: msgAndAction.0, andActions: msgAndAction.1)
}
}
}
The error methods:
//MARK: TouchID error
fileprivate func errorMessage(errorCode:Int) -> (strMessage: String, action: [UIAlertAction]){
var strMessage = ""
let cancelAction = UIAlertAction.init(title: Const.Localize.Common().kCancel, style: .cancel) { (cancelAction) in
}
var actions: [UIAlertAction] = [cancelAction]
switch errorCode {
case LAError.Code.authenticationFailed.rawValue:
biometricAuthentication { (success) in
//
}
case LAError.Code.userCancel.rawValue:
if biometryRetryCount == 2 {
blockUserFor24Hours()
} else {
showAlertOnCancelTapAction()
}
case LAError.Code.passcodeNotSet.rawValue:
strMessage = "Please goto the Settings & Turn On Passcode"
case LAError.Code.userFallback.rawValue:
biometryRetryCount -= 2
if biometryRetryCount == 0 {
blockUserFor24Hours()
} else {
biometricAuthentication { (success) in
//
}
}
default:
strMessage = evaluatePolicyFailErrorMessageForLA(errorCode: errorCode).strMessage
actions = evaluatePolicyFailErrorMessageForLA(errorCode: errorCode).action
}
return (strMessage, actions)
}
func evaluatePolicyFailErrorMessageForLA(errorCode: Int) -> (strMessage: String, action: [UIAlertAction]){
let cancelAction = UIAlertAction.init(title: Const.Localize.Common().kCancel, style: .cancel) { (cancelAction) in
}
var actions: [UIAlertAction] = [cancelAction]
var message = ""
if #available(iOS 11.0, macOS 10.13, *) {
switch errorCode {
case LAError.biometryNotAvailable.rawValue:
message = "Authentication could not start because the device does not support biometric authentication."
case LAError.biometryLockout.rawValue:
showPasscodeScreen()
case LAError.biometryNotEnrolled.rawValue:
message = "You do not have a registered biometric authentication. Kindly go to the settings and setup one"
let settingsAction = UIAlertAction.init(title: Const.Localize.Common().kSetting, style: .default) { (settingsAction) in
UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
}
actions.append(settingsAction)
default:
message = "Did not find error code on LAError object"
}
} else {
switch errorCode {
case LAError.touchIDLockout.rawValue:
showPasscodeScreen()
case LAError.touchIDNotAvailable.rawValue:
message = "TouchID is not available on the device"
case LAError.touchIDNotEnrolled.rawValue:
message = "You do not have a registered biometric authentication. Kindly go to the settings and setup one"
let settingsAction = UIAlertAction.init(title: Const.Localize.Common().kSetting, style: .default) { (settingsAction) in
UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
}
actions.append(settingsAction)
default:
message = "Did not find error code on LAError object"
}
}
return (message, actions)
}

touchID implementation error cancelled by user

How to resolve the TouchId error: Domain=com.apple.LocalAuthentication Code=-2 "Canceled by user."
I tried to add local context again:
let myContext = LAContext()
let myLocalizedReasonString = "Please use your last login for Inspyrus Supplier Central."
var authError: NSError?
if #available(iOS 8.0, macOS 10.12.1, *) {
if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString) { success, evaluateError in
DispatchQueue.main.async {
if success {
self.btnLoginClicked(UIButton())
} else {
print(evaluateError?.localizedDescription ?? "Failed to authenticate")
// Fall back to a asking for username and password.
// ...
}
}
}
}
}
You can check if the evaluateError returned from the evaluatePolicy call is a LAError.userCancel.
Something like this:
if success {
//...
}
else if let authError = evaluateError as? LAError {
switch authError.code {
case .userCancel:
// Authentication was canceled by user (e.g. tapped Cancel button).
break
default:
// Other error
break
}
// Or
switch authError {
case LAError.userCancel:
// Authentication was canceled by user (e.g. tapped Cancel button).
break
default:
// Other error
break
}
}

Detect when user tapped Don't Allow when making changes to photo library

When you want to make a change to a PHAsset, you wrap it up in a performChanges block. You get a success Bool and an error NSError in the completion block. Now I would like to show an alert to the user in the case the request failed. This does the trick:
PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
let request = PHAssetChangeRequest(forAsset: asset)
request.creationDate = date
}, completionHandler: { (success: Bool, error: NSError?) -> Void in
dispatch_async(dispatch_get_main_queue()) {
if let error = error {
//present alert
}
}
})
The problem is when the user taps Don't Allow it also presents the alert. I don't want to do that, the user intentionally canceled it so there's no need to inform them it failed. But how can I detect that's what has occurred? The error userInfo is nil, it doesn't seem it provides any useful info to detect that case. Am I missing something?
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
NSLog(#"%ld",(long)status);
switch (status) {
case PHAuthorizationStatusAuthorized:
// code for display photos
NSLog(#"ffefwfwfwef");
case PHAuthorizationStatusRestricted:
break;
case PHAuthorizationStatusDenied:
//code for Dont Allow code
break;
default:
break;
}
}];
This is now possible by checking if the error is a PHPhotosError and if so checking its code to see if it's .userCancelled.
PHPhotoLibrary.shared().performChanges({
let request = PHAssetChangeRequest(forAsset: asset)
request.creationDate = date
}) { success, error in
guard let error = error else { return }
guard (error as? PHPhotosError)?.code != .userCancelled else { return }
DispatchQueue.main.async {
//present alert
}
}

How to use Touch ID sensor in iOS 8

One of the most things I was excited about iOS 8 was the ability to use fingerprint sensors on the iPhone 5s and later. Unfortunately I cannot find out what is the required framework for that, nor how I can make authentication. Please help me with:
What framework required for using Touch ID?
How to use its methods and how to authenticate the user?
A code sample would be much appreciated.
More complete snippet, swift style:
func authenticateUser() {
// Get the local authentication context.
let context = LAContext()
// Declare a NSError variable.
var error: NSError?
// Set the reason string that will appear on the authentication alert.
var reasonString = "Authentication is needed to access your notes."
// Check if the device can evaluate the policy.
if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) {
[context .evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
if success {
}
else{
// If authentication failed then show a message to the console with a short description.
// In case that the error is a user fallback, then show the password alert view.
println(evalPolicyError?.localizedDescription)
switch evalPolicyError!.code {
case LAError.SystemCancel.toRaw():
println("Authentication was cancelled by the system")
case LAError.UserCancel.toRaw():
println("Authentication was cancelled by the user")
case LAError.UserFallback.toRaw():
println("User selected to enter custom password")
self.showPasswordAlert()
default:
println("Authentication failed")
self.showPasswordAlert()
}
}
})]
}
else{
// If the security policy cannot be evaluated then show a short message depending on the error.
switch error!.code{
case LAError.TouchIDNotEnrolled.toRaw():
println("TouchID is not enrolled")
case LAError.PasscodeNotSet.toRaw():
println("A passcode has not been set")
default:
// The LAError.TouchIDNotAvailable case.
println("TouchID not available")
}
// Optionally the error description can be displayed on the console.
println(error?.localizedDescription)
// Show the custom alert view to allow users to enter the password.
self.showPasswordAlert()
}
}
Source
The Local Authentication framework provides facilities for requesting authentication from users using Touch ID, following code snipped shows how you should request for authentication.
Objective C
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myReasonString = #"String explaining why app needs authentication";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myReasonString
reply:^(BOOL succes, NSError *error) {
if (success) {
// User authenticated successfully
} else {
// Authenticate failed
}
}];
} else {
// Could not evaluate policy; check authError
}
Swift
let myContext = LAContext()
var authError: NSError?
// Set the reason string that will appear on the authentication alert.
var myReasonString = "String explaining why app needs authentication"
if myContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &authError) {
[myContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: myReasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
if success {
// User authenticated successfully
} else {
// Authenticate failed
}
})]
} else{
// Could not evaluate policy; check authError
}
You're looking for LocalAuthentication framework (login may be required to see).
Basically you're interested in LAContext class and its
canEvaluatePolicy:error: and
evaluatePolicy:localizedReason:reply: methods.
The canEvaluatePolicy:error: method is used to check if TouchID authentication is available for you to use.
And use evaluatePolicy:localizedReason:reply: to perform actual authentication check
I was looking for an answer in objectiveC with all the possible errors. Didn't find on this post so here it is.
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Authenticate using your finger";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"User is authenticated successfully");
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
NSLog(#"Authentication Failed");
break;
case LAErrorUserCancel:
NSLog(#"User pressed Cancel button");
break;
case LAErrorUserFallback:
NSLog(#"User pressed Enter Password");
break;
case LAErrorPasscodeNotSet:
NSLog(#"Passcode Not Set");
break;
case LAErrorTouchIDNotAvailable:
NSLog(#"Touch ID not available");
break;
case LAErrorTouchIDNotEnrolled:
NSLog(#"Touch ID not Enrolled or configured");
break;
default:
NSLog(#"Touch ID is not configured");
break;
}
NSLog(#"Authentication Fails");
}
}];
} else {
NSLog(#"Can not evaluate Touch ID. This device doesn’t support one");
}
Also make sure to use dispatch_async otherwise your uialert messages will not pop-up on time. See sample code below
-(void)viewWillAppear:(BOOL)animated {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Touch ID Test to show Touch ID working in a custom app";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"Success" sender:nil];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:authError.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
}
Swift 3 version of #txulu response:
public func authenticateUser() {
// Get the local authentication context.
let context = LAContext()
// Declare a NSError variable.
var error: NSError?
// Set the reason string that will appear on the authentication alert.
var reasonString = "Authentication is needed to access your notes."
// Check if the device can evaluate the policy.
if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) {
[context .evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
if success {
// TODO - Guardar credencials
}
else{
// If authentication failed then show a message to the console with a short description.
// In case that the error is a user fallback, then show the password alert view.
print(evalPolicyError?.localizedDescription)
switch evalPolicyError!.code {
case LAError.systemCancel.rawValue:
print("Authentication was cancelled by the system")
case LAError.userCancel.rawValue:
print("Authentication was cancelled by the user")
case LAError.userFallback.rawValue:
print("User selected to enter custom password")
//self.showPasswordAlert()
default:
print("Authentication failed")
//self.showPasswordAlert()
}
}
} as! (Bool, Error?) -> Void)]
}
else{
// If the security policy cannot be evaluated then show a short message depending on the error.
switch error!.code{
case LAError.touchIDNotEnrolled.rawValue:
print("TouchID is not enrolled")
case LAError.passcodeNotSet.rawValue:
print("A passcode has not been set")
default:
// The LAError.TouchIDNotAvailable case.
print("TouchID not available")
}
// Optionally the error description can be displayed on the console.
print(error?.localizedDescription)
// Show the custom alert view to allow users to enter the password.
//self.showPasswordAlert()
}
}
Full Swift 5 version example snippet:
import LocalAuthentication
_
func authenticateUser() {
// Get the local authentication context.
let context = LAContext()
// Declare a NSError variable.
var error: NSError?
// Set the reason string that will appear on the authentication alert.
let reasonString = "Authentication is needed to provide access."
// Check if the device can evaluate the policy.
if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) {
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: Error?) -> Void in
if success {
print("Authentication successful! :) ")
} else {
// If authentication failed then show a message to the console with a short description.
// In case that the error is a user fallback, then show the password alert view.
print(evalPolicyError?.localizedDescription)
switch evalPolicyError!._code {
case LAError.authenticationFailed.rawValue:
print("### Authentication was cancelled by the system")
case LAError.userCancel.rawValue:
print("### Authentication was cancelled by the user")
case LAError.userFallback.rawValue:
print("### User selected to enter custom password")
self.showPasswordAlert()
default:
print("### Authentication failed")
self.showPasswordAlert()
}
}
})
} else {
// If the security policy cannot be evaluated then show a short message depending on the error.
switch error!.code{
case LAError.biometryNotEnrolled.rawValue:
print("### TouchID is not enrolled")
case LAError.passcodeNotSet.rawValue:
print("### A passcode has not been set")
default:
// The LAError.TouchIDNotAvailable case.
print("### TouchID not available")
}
// Optionally the error description can be displayed on the console.
print(error?.localizedDescription)
// Show the custom alert view to allow users to enter the password.
self.showPasswordAlert()
}
}
func showPasswordAlert() {
print("### showPasswordAlert")
}
Among these answers I was getting stuck every time I was running the authentication code.
Please make sure you Import LocalAuthentication to use LAContext and privacy check
With Swift 5 this is what worked for me.
import UIKit
import LocalAuthentication
class ViewController: UIViewController {
#IBOutlet weak var lbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func checkUserAuthentication(_ sender: Any) {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
[unowned self] success, authenticationError in
DispatchQueue.main.async {
if success {
//Authentication Success
self.lbl.text = "Great!! you are authorised"
} else {
let ac = UIAlertController(title: "Authentication failed", message: "Sorry!", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
}
}
} else {
let ac = UIAlertController(title: "Touch ID not available", message: "Your device is not configured for Touch ID.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
}

Resources