Refactoring: Face ID/Touch ID for iOS 13 Update

Back in February 2015, my article on Touch ID was published on raywenderlich.com. I was written in Swift for Xcode 8. Every year or so i would update the article as an author on the iOS Team. Here’s a link to the latest — How To Secure iOS User Data: The Keychain and Biometrics – Face ID or Touch ID. A few months ago, I had to update one of my own apps for iOS 13 with Apple’s biometric identification framework, Local Authentication. My app was also still supporting Objective-C so here’s follow up on what I had to change. As a bonus you can also take your user to Settings in case they have disabled

First thing is to add Local Authentication at the top of the Login view controller.


#import <LocalAuthentication/LocalAuthentication.h>

Next create an action for the Touch ID method:

- (IBAction)touchIDAction:(id)sender {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;

NSString *myLocalizedReasonString = @"Used for quick and secure access to the test app";
//...
}

After that we need to check if the device can support biometrics with canEvaluatePolicy and have an error ready.

Inside the touchIDAction add:

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
error:&authError]) {
// 1. successful steps
} else {
// 2. Oops. There's a error!
}

Inside the canEvaluatePolicy, we’ll use evaluatePolicy:localizedReason:reply. The reply will have a block that either succeeds or fails with our error.

// 1. successful steps.
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates

// using a Keychain utility method to get the email and password
NSString *passwordFound = [KeychainUtils getPasswordForUsername:self->emailTextField.text andServiceName:@"My_app" error:nil];
self->passwordTextField.text = passwordFound;
self->usingSecureID = true; // a Bool I added to keep track
[self loginAction:nil];
[NSLog showWithStatus:@"Logging_In"];
});
});
} else {
// User did not authenticate successfully, look at error and take appropriate action

//I'm using a showAlert method to bring up a UIAlertViewController
[self showAlert: @"There was a problem verifying your identity." withTitle:@"Error!"];
return;
}
}];

What do we do if there is an error enabling Face ID/Touch ID? It could be because the user has disabled the feature. What’s new is that we can now take the user to your application settings — without a hack.

Initially you can pop up an alert to inform the user. Added to UIKit in iOS 8, UIApplicationOpenSettingsURLString lets you add a button to the alert that will take the user to your app in Settings, where they can enable Face ID/Touch ID.

// Could not evaluate policy; look at authError and present an appropriate message to user
NSString *title = @"Error!";
  NSString *message = @"Your device cannot authenticate using TouchID.";
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {
// do we need to return animation?
                                                          }];
    // open your app in Settings
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    UIApplication *application = [UIApplication sharedApplication];
    NSString *settingTitle = @"Settings";
    UIAlertAction* settingsAction = [UIAlertAction actionWithTitle:settingTitle style:UIAlertActionStyleDefault
                                                           handler:^(UIAlertAction * action) {
                                                             [application openURL:url  options:@{}
completionHandler:nil];
                                                           }];
    [alert addAction:settingsAction];
    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
    return;
}

The whole method would look like this:

- (IBAction)touchIDAction:(id)sender {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;

NSString *myLocalizedReasonString = @"Used for quick and secure access to the test app";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
// 1. successful steps

[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates

// using a Keychain utility method to get the email and password
NSString *passwordFound = [KeychainUtils getPasswordForUsername:self->emailTextField.text andServiceName:@"My_app" error:nil];
self->passwordTextField.text = passwordFound;
self->usingSecureID = true; // a Bool I added to keep track
[self loginAction:nil];
[NSLog showWithStatus:@"Logging_In"];
});
});
} else {
// User did not authenticate successfully, look at error and take appropriate action

//I'm using a showAlert method to bring up a UIAlertViewController
[self showAlert: @"There was a problem verifying your identity." withTitle:@"Error!"];
return;
}
}];
} else {
// 2. Oops. There's a error!

// Could not evaluate policy; look at authError and present an appropriate message to user
NSString *title = @"Error!";
  NSString *message = @"Your device cannot authenticate using TouchID.";
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {
// do we need to return animation?
                                                          }];
    // open your app in Settings
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    UIApplication *application = [UIApplication sharedApplication];
    NSString *settingTitle = @"Settings";
    UIAlertAction* settingsAction = [UIAlertAction actionWithTitle:settingTitle style:UIAlertActionStyleDefault
                                                           handler:^(UIAlertAction * action) {
                                                             [application openURL:url  options:@{}
completionHandler:nil];
                                                           }];
    [alert addAction:settingsAction];
    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
    return;
}
}
}

Episode 219 – Acquisitions and Murders

Microsoft has bought GItHub. IBM is buying Red Hat. Apple bars Bloomberg from iPad event. All of the Apple Logos Included in the October 30 Event. Tim Mitra Blends Art and (Computer) Science at TD Bank. JAMF – There is no step three. New 2018 MacBook Air, 2018 Mac Mini, 2018 iPad Pro – 11” & 12.9”, and 2nd Gen. Apple Pencil. Picks: Designing for iPad Pro and Apple Pencil, Bringing Your Apps to iPad Pro, Shared Version Number trick

Episode 219 Show Links

Episode 219 Picks

Episode 215 – Left Handed Bird Flip

We fact check the size of the original iPhones, and AI For Accessibility. Our #askMTJC covers a video on economic principals, and swinging cats in man caves. We follow up on inviting users to TestFlight, countries that support iPhone XS eSIMs, Super Bowl commercials in Canada, and sluggish iOS 12 adoption. Apple Watch Series 4 Fall Detection Tested By a Hollywood Stunt Double. Microsoft Surface event 2018: the 5 biggest announcements. Picks: Adding Device Frames to iPhone XS and XS Max Screenshots with Shortcuts, sudo from Touch Bar.

Episode 215 Show Links:

Episode 215 Picks:

Episode 198 – WWDC 2018 Reflections

This week we give our impressions of WWDC 2018 keynote. We discuss Apple’s presenting the scholarship winner apps on the App Store. Microsoft’s purchase of GitHub. Apple is getting into the ad game to compete with other online players. The rumored iPad with face recognition is coming. We talk about the deprecation of OpenGL and OpenCL. Finally by Rene Richie guides our discussion of the WWDC announcements. Picks: UX Cake w/Jaime Lopez Jr, Machine Learning – Build a Model, App Store Review Guidelines Diff, Stevie the Snail, SpriteKit, PlayDead’s INSIDE

The cover image contains apps the hosts have worked on.

Episode 198 Show Links:

Episode 198 Picks:

Episode 159 – Walking Into Traffic

Our askMTJC wonders how many fingers we store on Touch ID. We follow up on how Apple will have us change how we use the next iPhone. We discuss how deep learning is used to shape Siri’s voice, the cost of building apps, and HDR video. Jaime tells us about Microsoft and Amazon’s will combine digital assistants. You can check which of your iOS apps won’t work with iOS 11. Apple and Accenture will partner to build apps. We look at Google’s release of ARCore as an answer to ARKit. Picks: WTF Auto Layout, HIG: Augmented Reality, 360|iDev 2017 Highlights.

Photo: Pixabay

Episode 159 Show Links:

Episode 159 Picks:

Episode 151 – A Sticky Wicket

We marvel at the fortitude of new fans who listen to our whole back catalog of shows. We discuss the inability to share IAP with Family Sharing, the most recent iPhone 8 wireless charging and Touch ID rumors as well as PhotoBucket’s “ransoming” long time users of there “free” service. We dig into Password Autofill and mechanically converting Objective-C projects to Swift. Picks: Over 150 of the Best Machine Learning, NLP, and Python Tutorials I’ve Found, Laura Savino’s tip on Simulator devices, Debugging UIStackViews and iOS 11 lets you scan a router’s QR code to quickly join a network.

Podcast Tip of the Week: Debugging UIStackViews
view.isAccessibilityElement = true
yourStackView.accessibilityLabel = "blah"
Then use View Debugger,
see Accessibility -> description

Episode 151 Show Links:

Episode 151 Picks:

Episode 142 – Leading From Behind

This week we follow up on finger print dongles, misuses of Engineering titles and Google’s new Canadian adventures in Waterloo. We discuss Apple vs Uber, Apple’s quarterly number as see by Kevin O’Leary and major app publisher’s abandoning the Watch, for now. Apple is looking into space and satellites. Picks: Increment, XChange – Share Business Cards Instantly and RWDevcon 2017 Vault

Sponsored by: Buddy Build

Episode 142 Show Links:

Episode 142 Show Picks:

Episode 140 – Carrying the Shield

We follow up on Apple and semiconductors with rumored purchase of chip manufacturers, OLED screen delays and Touch ID issues. We also follow up on MyScript Calculator for handwriting calculations now on iPad. We discuss the Developer Survey Results 2017 from Stack Overflow. Apple has also made iWork, Garage Band and iMovie free for all users. Apple has also acquired a California permit for self-driving cars. Coachella attendees use Find My iPhone to recover 100+ stolen devices. The Mac Pro makes an appearance again. Picks: Analyzing 3rd party libraries, Silicon Valley iOS Developer Meetup, 17 Xcode Tips and Tricks That Every iOS Developer Should Know, Software Library: Macintosh, ABI stability and WWDC Family

Episode 140 Show Links:

Episode 140 Picks:

Episode 116 – Back to the Future of Desktop

This week we answer questions from #askMTJC about the Axiotron ModBook and Core Data. We follow up on the delayed AirPods and removal of the Edition Watches from high end stores. We also follow up on the appearance of the ARM chip support in the macOSX kernel and the upcoming Touch ID feature in the new MacBook Pros. We discuss the new Microsoft Surface Studio and its potential impact on Apple. We touch on AppWage, Designing for Empathy and the new Swift Server APIs workgroup. Picks: Fatal Error Podcast, Functional Swift Conference videos and Nebo by MyScript

Sponsored by: Hired

Episode 116 Show Notes:

Episode 116 Picks:

Episode 79 – Your Back Door Man

This week we discuss the Letter published by Tim Cook in response to the FBI’s request to create a “back door” into iOS. We talk about Panic’s Prompt app update. We ponder Rob Rhyne’s departure to join Apple and Jaimee Newberry’s rise to COO of MartianCraft. Greg sneaks in a couple of posts on Blackfish and Swifter; two Swift based http servers. Picks: Quartz iOS App, Earl Grey and The Astonishing Powers and Mesmerizing Secrets of 3D Touch.

Episode 79 Show Notes:

Episode 79 Picks: