Reputation: 261
I want to use TouchID authenticate my own app.
1.I want user can click 'Enter passcode' to invoke system build-in passcode screen to authenticate,if success then enter my own app.
But I don't how know to make it forward to passcode authenticate view like the following screen in 'case LAErrorUserFallback'
Here is my code :
LAContext *context = [[LAContext alloc] init];
__block NSString *msg;
__block BOOL bAuth;
// show the authentication UI with our reason string
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(@"Unlock APP With FingerPrint", nil) reply:
^(BOOL success, NSError *authenticationError) {
if (success) {
bAuth = YES;
msg =[NSString stringWithFormat:NSLocalizedString(@"EVALUATE_POLICY_SUCCESS", nil)];
dispatch_async(dispatch_get_main_queue(), ^{
[[MYAppDelegate theDelegate] initializeAppAfterKeyVaultUnlocked];
});
NSLog(@"%@",msg);
} else {
bAuth = NO;
switch (authenticationError.code) {
case LAErrorAuthenticationFailed:
msg = [NSString stringWithFormat:NSLocalizedString(@"Authentication Failed", nil)];
// ...
break;
case LAErrorUserCancel:
msg = [NSString stringWithFormat:NSLocalizedString(@"User pressed Cancel button", nil)];
dispatch_async(dispatch_get_main_queue(), ^{
[[MYAppDelegate theDelegate] exitAndLock];
});
break;
case LAErrorUserFallback:
msg = [NSString stringWithFormat:NSLocalizedString(@"User pressed \"Enter Password\"", nil)];
//Here I want to fallback to iOS build-in passcode authenticate view, and get the auth result.
break;
default:
msg = [NSString stringWithFormat:NSLocalizedString(@"Touch ID is not configured", nil)];
// ...
break;
}
NSLog(@"%@",authenticationError.localizedDescription);
}
}];
Upvotes: 14
Views: 10763
Reputation: 79646
Replace LAPolicy
policy enum value deviceOwnerAuthenticationWithBiometrics
with deviceOwnerAuthentication
Note: If user has enable
biometric
(face id or touch id) authentication, then device will ask first for biometric authentication and if user choose fall back authentication, then onlydeviceOwnerAuthentication
will show passcode screen.
Try this and see (swift 4):
func touchIDAuthentication() {
let context = LAContext()
var error:NSError?
// edit line - deviceOwnerAuthentication
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
//showAlertViewIfNoBiometricSensorHasBeenDetected()
return
}
// edit line - deviceOwnerAuthentication
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &errorPointer) {
// edit line - deviceOwnerAuthentication
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason, reply: { (success, error) in
if success {
DispatchQueue.main.async {
print("Authentication was successful")
}
}else {
DispatchQueue.main.async {
//self.displayErrorMessage(error: error as! LAError )
print("Authentication was error")
}
}
})
}else {
// self.showAlertWith(title: "Error", message: (errorPointer?.localizedDescription)!)
}
}
Upvotes: 0
Reputation: 996
For your case :
case LAErrorUserFallback:
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:NSLocalizedString(@"Unlock APP With PassCode", nil) reply: ^(BOOL success, NSError *authenticationError) {
if(success){
NSLog(@"PassCode Login successful");
}else{
NSLog(@"%@",authenticationError);
}
}
For device passcode verification you need to use LAPolicyDeviceOwnerAuthentication instead of LAPolicyDeviceOwnerAuthenticationWithBiometrics. Hope this helps !!
Upvotes: 1
Reputation: 4622
Now in iOS 9 it is pretty simple actually - you just have to use LAPolicyDeviceOwnerAuthentication
instead of LAPolicyDeviceOwnerAuthenticationWithBiometrics
So in your code you just replace this:
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(@"Unlock APP With FingerPrint", nil) reply:
^(BOOL success, NSError *authenticationError) {
With this:
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:NSLocalizedString(@"Unlock APP With FingerPrint", nil) reply:
^(BOOL success, NSError *authenticationError) {
Thus, when user fails to authenticate with fingerprint, there'd be "enter passcode" option which would invoke system passcode input screen.
Upvotes: 13
Reputation: 924
Didn't try that, but this post claim you can use the system as follow here (This works only with iOS 8 or later).
Or (which is what I did) you can build your passcode entry screen (to support older iOS versions), my controller have a passcode entry view, which will get exposed when the user select use passcode. At that point the call back from evaluatePolicy will return with LAErrorUserFallback, which can be the time to open your custom passcode screen.
something like that:
-(void)maybeShowTouchIDMessage {
if (![SettingsManager sharedManager].isUseTouchID || self.createPassCodeMode) {
self.shieldView.hidden = YES;
return;
}
self.shieldView.hidden = NO;
self.shieldView.alpha = 1.0;
LAContext *context = [[LAContext alloc] init];
NSError *evalError = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&evalError] ) {
__weak SecurityWindowViewController *weakSelf = self;
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:@"Use touch id \n or hit \"Cancel\" to enter passcode"
reply:^(BOOL success, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
SecurityWindowViewController *strongSelf = weakSelf;
if (success) {
[strongSelf hideWithSuccess:YES];
} else if (error){
NSString *errorMessage;
BOOL showError = NO;
switch (error.code) {
case LAErrorAuthenticationFailed:
errorMessage = @"Sorry couldn't autheticate";
showError = YES;
break;
case LAErrorPasscodeNotSet:
errorMessage = @"Sorry couldn't autheticate";
showError = YES;
break;
case LAErrorTouchIDNotEnrolled:
errorMessage = @"Touch ID has no enrolled fingers";
showError = YES;
break;
default:
showError = NO;
break;
}
[UIView animateWithDuration:0.5 animations:^{
strongSelf.shieldView.alpha = 0.0;
} completion:^(BOOL finished) {
strongSelf.shieldView.hidden = YES;
}];
if (showError) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:errorMessage
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alert show];
}
}
});
}];
}
Upvotes: 1
Reputation:
You can add another case and call your passcode screen from that.
Here is my code:
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = strMessage;
objFlockr.pVerificationBlock = objResponse;
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
if (!isShow) {
myContext.localizedFallbackTitle = @"";
}
else
{
myContext.localizedFallbackTitle = @"Set Up Passcode";
}
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL succes, NSError *error) {
if (!AppDel.firstAttampt && succes && !isShow)
{
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(1);
}
else if (succes) {
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(0);
NSLog(@"User authenticated");
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
NSLog(@"Authentication Failed");
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(1);
break;
case LAErrorUserCancel:
NSLog(@"User pressed Cancel button");
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(3);
break;
case LAErrorUserFallback:
NSLog(@"User pressed \"Enter Password\"");
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(4);
break;
default:
[self showMessage:@"Touch ID is not configured" withTitle:@"Error"];
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(2);
NSLog(@"Touch ID is not configured");
break;
}
NSLog(@"Authentication Fails");
}
}];
} else {
NSLog(@"Can not evaluate Touch ID");
[self showMessage:@"Can not evaluate TouchID" withTitle:@"Error"];
}
Upvotes: 0
Reputation: 31
In my understanding, you will have to build the passcode screen yourself if you want to use evaluatePolicy.
If you use keychain, the SecItemCopyMatching function automatically falls back to passcode if fingering fails. Here's a reference on how to get it going (see section 3): https://www.secsign.com/fingerprint-validation-as-an-alternative-to-passcodes/
Upvotes: 1