Table of contents
Open Table of contents
Introduction
Facial recognition and fingerprint technology, such as FaceID and TouchID, has become increasingly popular in modern mobile devices. In this tutorial, we will show you how to use the FaceID and TouchID functionality in your SwiftUI applications to provide increased security and convenience for your users.
Basic Functionality
import LocalAuthentication
import Foundation
class LocalAuthenticationService {
class func authenticateWithBiometrics(_ completion: @escaping (Result<Void, Error>) -> Void) {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "We need to unlock your data."
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
if success {
completion(.success(()))
} else {
completion(.failure(AppError.error(error?.localizedDescription ?? "Error Undefined")))
}
}
} else {
completion(.failure(AppError.error("No Biometrics Available")))
}
}
}
This code presents a Swift class called LocalAuthenticationService
that provides an easy way to use the biometric authentication functionality in your application. The static method authenticateWithBiometrics
is the one that provides the authentication functionality. This method takes a callback function as a parameter that is executed when the authentication is completed.
The authenticateWithBiometrics
function creates an instance of LAContext, which is an iOS class that provides access to the biometric authentication functionality. It checks if the device is compatible with biometric authentication and if the user has set up a fingerprint or face to use as a security measure. If it is compatible, the evaluatePolicy
method is called on the context with the argument .deviceOwnerAuthenticationWithBiometrics
. This method displays a dialog for the user to authenticate using their fingerprint or face. The localizedReason
argument is a string that is displayed in the dialog to indicate to the user the reason for the authentication request.
The parameter of evaluatePolicy
is a callback block that is called when the user has authenticated. If the user has authenticated successfully, the callback function is called with a Success Result. If it does not authenticate successfully, the callback function is called with an Error Result. The error result may be the error returned in case of authentication failure or “No Biometrics Available” if the device does not support biometric authentication.
Before continuing we have to add the NSFaceIDUsageDescription
key to our Info.plist
, NSFaceIDUsageDescription
is an Info.plist
key that is used to describe the purpose of using facial recognition technology (Face ID) in the application. It is necessary to include this key in your project’s Info.plist
file if your application uses Face ID for user authentication.
The reason for this is that, according to Apple’s development guidelines, all applications that use private system features, such as Face ID, must provide a clear and accurate description of the use of these features. This provides transparency for users about how their biometric information will be used, and allows them to make an informed decision.
LockScreen
Now, let’s see how we can use the authenticateWithBiometrics
function with an example:
import SwiftUI
struct LockScreenView<Content: View>: View {
// State variable to indicate if the view is unlocked or not
@State private var isUnlocked = false
// Access the current scene phase/state
@Environment(\.scenePhase) var scenePhase
// Content to be displayed
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
Group {
// If the view is unlocked, show the content
if isUnlocked {
content
} else {
// If not unlocked, show a biometric unlock view
UnlockWithBiometricsView(action: authenticateWithBiometrics)
}
}
// Listen to scene phase change
.onChange(of: scenePhase) { newPhase in
// If the phase changes to background, lock the content
if newPhase == .background {
isUnlocked = false
}
}
}
func authenticateWithBiometrics() {
// Call the local authentication service to authenticate with biometrics
LocalAuthenticationService.authenticateWithBiometrics { result in
switch result {
case .success():
// If successful, unlock the view
isUnlocked = true
case .failure(let error):
// If failed, print the error message
print(error.localizedDescription)
}
}
}
}
This code shows a SwiftUI structure called LockScreenView
that can be used to display content in an application with a lock screen. The structure takes a generic parameter Content
that must be a SwiftUI view.
The structure has a state isUnlocked
that indicates if the content is unlocked or not. It also has a scenePhase
property that is used to listen for the change in the application scene state.
The structure has an initializer that takes a view building function that is used to create the content to be displayed. In the body of the structure, the unlock view calls the authenticateWithBiometrics
method to authenticate the user.
The authenticateWithBiometrics
method calls the local authentication service to authenticate the user with biometrics. If the authentication is successful, the isUnlocked state is changed to true to unlock the content. If it fails, an error message is printed.
The body of the structure also has a listener for the change in scene state. If the state changes to background, the content is locked by changing the isUnlocked
state to false. This is important if we want to protect the information after the application goes to the background.
Example
Finally, let’s see how easy it is to use the LockScreenView
view:
import SwiftUI
struct ContentView: View {
var body: some View {
// Wrap the content in a LockScreenView
LockScreenView {
// Content
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}
}
}
Within the LockScreenView
structure is the actual content of the application, in this case a VStack
that contains an image and text.
Conclusion
To summarize, in this tutorial we have learned how to use biometric authentication functionality in a SwiftUI application. We have seen how to create a local authentication service class that uses LAContext to authenticate the user with their fingerprint or face. We have also seen how to use this service class in a custom lock screen view called LockScreenView
to protect the application’s content. Finally, we have seen how to use LockScreenView
to protect the application’s content in the main view.
I hope this tutorial has provided you with a better understanding of how to use biometric authentication functionality in your SwiftUI applications. Remember that this is just one way to implement this functionality, and there are many other ways to protect the content of your application. It is always important to evaluate the security needs of your application and choose the best solution for your specific use case.