¿Cómo usar Face ID o Touch ID en tu app con SwiftUI?

En Swift y SwiftUI podemos usar la autenticación biométrica para detectar que el propietario del iPhone está usando la aplicación. De esta manera proporcionamos una capa de seguridad extra con los datos biométricos del usuario, ya sean Touch id o Face Id

SwiftBeta

Tabla de contenido


👇 SÍGUEME PARA APRENDER SWIFTUI, SWIFT, XCODE, etc 👇

Hoy en SwiftBeta vamos a aprender a cómo usar autenticación biométrica para poder desbloquear ciertas partes de nuestra app. Vamos hacer lo mismo que cuando queremos desbloquear el iPhone, hace unos años con ciertos dispositivos podíamos usar el TouchId, y con la Huella dactilar del usuario del iPhone podíamos desbloquear el iPhone en lugar de poner el código de seguridad, y recientemente con los nuevos iPhones, ahora podemos usar FaceId para desbloquear nuestro dispositivo. La verdad que muy cómodo este método de autenticación.

Pues bien, en el video de hoy vamos a aprender a cómo usar esta autenticación biométrica, y usaremos una opción del simulador de Xcode para hacer este tipo de autenticaciones. Añadir este tipo de autenticación es útil dentro de apps que quieran añadir un extra en seguridad a ciertas partes de la aplicación, como a ciertas fotos, mensajes, validar ciertas operaciones, etc. Dependerá de tu app y los casos de uso que quieras usar. En el video de hoy vamos a revelar un mensaje secreto si la autenticación biométrica ha sido un éxito.

Creamos proyecto en Xcode

Lo primero de todo que vamos hacer es crear el proyecto en Xcode, voy a llamar al proyecto SwiftBetaBiometric, y muy importante en Interface vamos a seleccionar SwiftUI.

Una vez creado el proyecto, vamos a centrarnos en la vista ContentView, ya que es la única en la que vamos a trabajar, va a ser un video muy chulo y sencillo.

Modificamos ligeramente la vista, y añadimos el siguiente código en el body:

struct ContentView: View {
    @State var canShowSecretMessage: Bool = false
    
    var body: some View {
        VStack {
            Button(action: {
                // TODO:
            }, label: {
                VStack {
                    Image(systemName: "faceid")
                        .font(.system(size: 120))
                        .foregroundStyle(.tint)
                    Text("Pulsa para revelar el secreto")
                        .padding(.top, 20)
                }
            })
            if canShowSecretMessage {
                Text("¡Suscríbete a SwiftBeta para apoyar el canal! 🚀")
                    .font(.largeTitle)
                    .bold()
                    .padding()
            }
        }
        .offset(y: -100)
        .padding()
    }
}

Importar framework LocalAuthentication

Lo siguiente que vamos hacer es importar el framework LocalAuthentication, este framework nos va a proporcionar toda la implementación necesaria para usar el Touch ID y el Face ID.

import LocalAuthentication

Lo siguiente que vamos hacer es crear una propiedad que sea de tipo LAContext, es un tipo especia donde LA son las siglas del framework que acabamos de importar, LocalAuthentication. Y el contexto lo vamos a usar para 2 cosas:

  • El contexto nos va a decir si el dispositivo donde estamos ejecutando el código soporta autenticación biométrica.
  • Y también vamos a usar el contexto para iniciar el proceso de autenticación.
struct ContentView: View {
    var canShowSecretMessage: Bool = false
    let context = LAContext()
    ...
}

Una vez tenemos la referencia del contexto, vamos a comprobar que el device soporta autenticación biométrica. Vamos a crear un método llamado authenticate que se llame cada vez que se pulsa el Button de ContentView:

func authenticate() {
   // TODO
}

Context canEvaluatePolicy

Y dentro de este método vamos a crear la implementación, lo primero, saber que el device soporta la autenticación biométrica, vamos a usar un método del contexto llamado canEvaluatePolicy:

func authenticate() {
    if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: <#T##NSErrorPointer#>)
}

Al hacerlo, vemos que el primer parámetro es un case de un enum, pero en el segundo nos pide un tipo NSError, este tipo es un Error de Objective-C, el método necesita una referencia a este tipo de error por si en caso de ocurrir uno, no de toda la información. Pues creamos una variable dentro del método authenticate, la vamos a llamar error y va a ser de tipo NSError opcional.

var error: NSError?

Y se la pasamos al método canEvaluatePolicy de la siguiente manera:

func authenticate() {
    var error: NSError?
    
    if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error){
        
    } else {
        print("El dispositivo no soporta autenticación Biométrica")
    }
}

Si el dispositivo soporta autenticación biométrica entraremos dentro del if, y sino entraremos dentro del else.

Context evaluatePolicy

Una vez hemos hecho esta parte, ahora vamos a realizar la autenticación. Justo dentro del if vamos a llamar a otro método del context llamado evaluatePolicy.

Este método espera 2 parámetros, el primero es indicarle el policy, aquí vamos a usar la misma de antes, la de authenticationWithBiometrics, y el segundo parámetro es para indicarle al usuario un mensaje de por qué necesita autenticarse, depende de la funcionalidad de nuestra app podemos hacerlo más específico o más general, en mi caso voy a indicar que es para revelar el mensaje secreto de la app. Y finalmente, el resultado lo obtenemos un trailing closure.

func authenticate() {
    var error: NSError?
    
    if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error){
        
        context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Por favor autentícate para continuar") { success, error in
            if success {
                canShowSecretMessage.toggle()
            } else {
                print("Error en la autenticación biométrica")
            }
        }
        
    } else {
        print("El dispositivo no soporta autenticación Biométrica")
    }
}
}

Dentro del closure, recibimos un Booleano indicando si todo ha ido bien, y también obtenemos un error. Si todo va bien vamos a revelar el mensaje secreto, y sino printaremos un mensaje de error.

Compilar para probar la autenticación biométrica

Una vez hemos llegado hasta aquí, ya lo tenemos todo listo para compilar y probar nuestra app. Vamos a compilar la app en el simulador de Xcode.

Pero, ¿qué ocurre si pulsamos en el Button? Tenemos un crash, y si miramos más de cerca no está dando la solución. Debemos usar la key NSFaceIDUsageDescription con un texto, para indicar al usuario por qué queremos usar Face ID dentro de la app. Vamos a ello, vamos a nuestro proyecto, a targets, y ahí en Info añadimos una Key con el texto que queramos, en mi caso voy a poner "Autenticación biométrica para mostrar secretos".

Ahora vamos a compilar de nuevo y vamos a pulsar el Button. En este caso obtenemos un mensaje de error por la consola diciendo que el dispositivo no soporta la autenticación biométrica. Vamos a solucionarlo debemos indicarle al simulador que nuestra app puede usar Face ID, vamos al menu del simulador, en Features -> Face ID y activamos Enrolled. Ahora si volvemos a compilar nos debería de aparecer un alert indicando si queremos usar Face ID dentro de nuestra app, le damos a OK, y seguidamente nos aparece una ventana para que nosotros indiquemos si queremos que la autenticación sea correcta o que falle. Vamos a hacer que funcione, volvemos al menu del simulador en Features -> Face ID -> Matching Face, y MAGIA! cómo ha sido un success, aparece el mensaje secreto de ¡Suscríbete a SwiftBeta para apoyar el canal! 🚀

Ahora, vamos a volver a compilar y vamos a probar el otro estado, el estado en que la autenticación biométrica falla.

Al hacerlo aparece una animación indicando que no ha reconocido nuestra cara y si queremos volver a intentarlo, si le damos a cancelar vemos que aparece el mensaje de Error en la autenticación biométrica.

Conclusión

Hoy hemos aprendido a cómo usar un framework que no habíamos visto hasta ahora en el canal llamado LocalAuthentication, este framework nos sirve para realizar autenticaciones para validar que el usuario que está usando la app es el propietario del dispositivo.

Y hasta aquí el video de hoy!