En Solid GEAR desarrollamos aplicaciones móviles, iOS y Android, y acompañamos a nuestros clientes en el ciclo de vida de las apps, desde la conceptualización, desarrollo, publicación en los markets (Apple Store o Google Play) así como su mantenimiento futuro. Este mantenimiento es necesario, entre otras razones, para cumplir con los requisitos que nos fijan los markets, en este caso la integración de Apple ID.
¿Qué es y por qué tengo que usarlo?
La autenticación con Apple proporciona lo necesario para registrarse y acceder a tu aplicación móvil usando tu Apple ID. Esta nueva característica está disponible desde iOS 13. A partir de Abril de 2020 Apple obliga a que tu aplicación móvil lo implemente si has implementado el inicio de sesión con algún método de login de terceros. Si no es así no es necesario que lo incluyas. En este artículo vamos a ver cómo hacerlo. Empecemos este tutorial que nos servirá para registrarnos y llevar a cabo la autenticación con Apple ID de Apple.
¿Por dónde empezamos?
Lo primero es añadir a tu aplicación la Capability Sign In with Apple. Para ello en Xcode seleccionamos nuestro proyecto y en la pestaña Signing & Capabilities añadimos Sign In with Apple.
Añadir los frameworks necesarios
En esta ocasión necesitaremos el framework AuthenticationServices que está disponible a partir de iOS 12 y se encarga entre otras cosas de manejar las contraseñas almacenadas en el keychain. Ahora en iOS 13 se encarga también del Sign In. En nuestro proyecto en Xcode en la pestaña General, en el apartado Frameworks, Libraries and Embedded Content pulsamos el botón +, lo buscamos entre la lista de frameworks que aparecen y lo añadimos.
El botón de Iniciar sesión con Apple
Aunque realmente no se trata de un botón, ya que hereda de UIControl y no de UIButton, es el elemento de interfaz que nuestros usuarios van a tener que pulsar para arrancar el proceso de autenticación o registro mediante Apple Sign. Que este elemento no sea realmente un botón tiene que tenerse en cuenta ya que, por ejemplo para habilitarlo o deshabilitarlo si usamos la propiedad isEnabled el elemento se deshabilitará, pero no cambiará su UI como sucede con los botones que en este caso se muestran visualmente deshabilitados. Esto no supone ningún problema ya que podemos modificarlo usando un alpha, cambiando su color, etc. Actualmente, mayo de 2020, existen algunos problemas detectados, el más importante que nos afecta ahora mismo es el evento touchUpInside es que no responde correctamente, por lo que usaremos touchDown. Veamos una posible implementación de este botón:
import AuthenticationServices
…
// Añadir ASAuthorizationControllerDelegate
en la clase en la que vamos a mostrar el Apple Sign In para cumplir los delegados.
…
//En este ejemplo usaremos una vista para incluir dentro nuestro botón
@IBOutlet var appleSingView:UIView!
…
if #available(iOS 13.0, *) {
guard appleSignButton == nil else { return }
appleSignButton = ASAuthorizationAppleIDButton()
appleSignButton?.addTarget(self, action: #selector(appleIDButtonPress), for: .touchDown)
appleSignButton?.frame = appleSingView.bounds
appleSignButton?.cornerRadius = buttonCornerRadius
guard let appleSignButton = appleSignButton else { return }
appleSingView.addSubview(appleSignButton)
appleSingView.isHidden = false
}
Es necesario importar AuthenticationServices, además si nuestra aplicación móvil es compatible con anteriores versiones de iOS debemos incluir este código sólo si el dispositivo en el que se ejecuta tiene instalado iOS 13 o superior.
¿Qué ocurre cuando el botón se pulsa?
Implementamos aquí la lógica que se ejecuta cuando el usuario decide registrarse o acceder mediante Sign in .
@objc func appleIDButtonPress() {
if #available(iOS 13.0, *) {
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self as? ASAuthorizationControllerPresentationContextProviding
authorizationController.performRequests()
}
}
Lo primero es crear la instancia de ASAuthorizationAppleIDProvider con que la que se generará la petición de autenticación con AppleID al llamar al método createRequest(). Tras esto añadiremos los scopes actualmente disponibles que son nombre y correo. Creamos authorizationController y seleccionamos self en delegate y presentationContextProvider para tener control de las acciones del usuario y para saber desde que ventana se abrirá el diálogo. Por último se llama al método performRequests().
Además para poder obtener la ventana en la que se presentará el diálogo se debe añadir el siguiente método:
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return self.view.window!
}
El diálogo de Apple Sign
Una vez pulsado el botón aparecerá la el diálogo que permite al usuario autenticarse con Apple ID. La primera pantalla que aparecerá nos muestra información sobre el Sign in de Apple. Como se puede ver en la imagen:
Tras darle a continuar el usuario tendrá opción de compartir con esta aplicación su email, o compartir un mail generado aleatoriamente por Apple. Este mail generado por Apple será el mismo la próxima vez que se use esta autenticación. Esto es debido a que algunas aplicaciones móviles basan las cuentas de sus usuarios en un correo electrónico válido.
Apple Sign In también permite compartir con la aplicación un nombre de usuario distinto al que se usa en el Apple ID. Si el usuario pulsa la casilla NAME se mostrará la siguiente pantalla:
Una vez terminado el proceso sólo queda continuar. A continuación aparecerá una vista en la que introducir la contraseña o los correspondientes signos que indican que se están utilizando las autenticaciones biométricas de iOS.
¿Y ahora qué?
Si se ha completado correctamente la autenticación del Apple Sign In en nuestra aplicación móvil se lanzará el siguiente método que deberemos implementar :
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else { return }
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
// Aquí se incluirá la lógica de registro y de autenticación de nuestra app que usará userIdentifier y opcionalmente el resto de información
}
Otra posible implementación del método sería la siguiente, en la que además se comprueba y gestiona si se ha utilizado un password almacenado en el iCloud Keychain.
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName
let email = appleIDCredential.email
// Aquí se incluirá la lógica de registro y de autenticación de nuestra app que usará userIdentifier y opcionalmente el resto de información
case let passwordCredential as ASPasswordCredential:
let username = passwordCredential.user
let password = passwordCredential.password
// Aquí irá la lógica de autenticación cuando se esté usando un usuario y password de los almacenados en el keychain.
default: break
}
}
Recordar que en el caso de que nuestra app no haya permitido el uso de iCloud Keychain, algo para lo que deberá estar preparada, la implementación que necesitamos será la primera.
Otro método importante es el siguiente, en el que se gestionarán los errores al realizar la autenticación.
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// Lógica para la gestión de errores en la autenticación.
}
Para gestionar los credenciales ya existentes implementamos el siguiente método al cargar el viewController del login:
func performExistingAccountSetupFlows() {
let requests = [ASAuthorizationAppleIDProvider().createRequest(),
ASAuthorizationPasswordProvider().createRequest()]
let authorizationController = ASAuthorizationController(authorizationRequests: requests)
authorizationController.delegate = self
authorizationController.presentationContextProvider = self as? ASAuthorizationControllerPresentationContextProviding
authorizationController.performRequests()
}
Nota: La segunda implementación del método authorization
Y con esto ya tendríamos todo lo necesario para incluir el Apple Sign In en nuestra aplicación móvil.
Si estás interesado en el desarrollo iOS puedes visitar algunas de estas interesantes entradas:
Firebase y Notificaciones Push en iOS
iOS: Gráfico de barras sencillo en Swift con UIStackViews
Desarrolla tu app iOS securizada con Face ID y Touch ID
Si quieres comentar con nosotros el desarrollo de tu app iOS o Android, ¡escríbenos!