To finish off our app, we’re going to make one last important change: we’re going to require the user to authenticate themselves using either Touch ID or Face ID in order to see all the places they have marked on the app. After all, this is their private data and we should be respectful of that, and of course it gives me a chance to let you use an important skill in a practical context!
First we need some new state in our view model that tracks whether the app is unlocked or not. So, start by adding this new property:
var isUnlocked = false
Second, we need to add the Face ID permission request key to our project configuration options, explaining to the user why we want to use Face ID. If you haven’t added this already, go to your target options now, select the Info tab, then right-click on any existing row and add the “Privacy - Face ID Usage Description” key there. You can enter what you like, but “Please authenticate yourself to unlock your places” seems like a good choice.
Third, we need to add import LocalAuthentication
to the top of your view model’s file, so we have access to Apple’s authentication framework.
And now for the hard part. If you recall, the code for biometric authentication was a teensy bit unpleasant because of its Objective-C roots, so it’s always a good idea to get it far away from the neatness of SwiftUI. So, we’re going to write a dedicated authenticate()
method that handles all the biometric work:
LAContext
so we have something that can check and perform biometric authentication.isUnlocked
to true so we can run our app as normal.Add this method to your view model now:
func authenticate() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Please authenticate yourself to unlock your places."
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
if success {
self.isUnlocked = true
} else {
// error
}
}
} else {
// no biometrics
}
}
Remember, the string in our code is used for Touch ID, whereas the string in Info.plist is used for Face ID.
And now we need to make an adjustment that is in reality very small, but can be hard to visualize if you’re reading this rather than watching the video. Everything inside the body
property needs to be indented in by one level, and have this placed before it:
if viewModel.isUnlocked {
Then at the end of the body
property add this to close the condition and leave space for an unlock button:
} else {
// button here
}
So now we all we need to do is fill in the // button here
comment with an actual button that triggers the authenticate()
method. You can design whatever you want, but something like this ought to be enough:
Button("Unlock Places", action: viewModel.authenticate)
.padding()
.background(.blue)
.foregroundStyle(.white)
.clipShape(.capsule)
You can now go ahead and run the app again, because our code is almost done. If this is the first time you’ve used Face ID in the simulator you’ll need to go to the Features menu and choose Face ID > Enrolled, but once you relaunch the app you can authenticate using Features > Face ID > Matching Face.
And with that our code is done, and that’s another app complete – good job!
SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure and A/B test your entire paywall UI without any code changes or app updates.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.