Puedes permitir que tus usuarios se autentiquen con Firebase mediante su Cuenta de Google al integrar el Acceso con Google en tu app.
Antes de comenzar
- Agrega Firebase a tu proyecto de iOS. Incluye los siguientes pods en el
Podfile
:pod 'Firebase/Auth' pod 'GoogleSignIn'
- Si aún no has conectado la app a tu proyecto de Firebase, puedes hacerlo desde Firebase console.
- Sigue estos pasos para habilitar el Acceso con Google en Firebase console:
- En Firebase console, abre la sección Auth.
- En la pestaña Método de acceso, habilita el método de Google y haz clic en Guardar.
1. Importa los archivos de encabezado requeridos
Para comenzar, debes importar a la app los archivos de encabezado del SDK de Firebase y del SDK de Acceso con Google.
Swift
En el delegado de la app, importa los siguientes archivos de encabezado:
import Firebase import GoogleSignIn
En el controlador de vista de tu vista de acceso, importa los siguientes archivos de encabezado:
import Firebase import GoogleSignIn
Objective-C
En el delegado de la app, importa los siguientes archivos de encabezado:
@import Firebase; @import GoogleSignIn;
En el controlador de vista de tu vista de acceso, importa los siguientes archivos de encabezado:
@import Firebase; @import GoogleSignIn;
2. Implementa el Acceso con Google
Sigue estos pasos para implementar el Acceso con Google. Consulta la documentación para desarrolladores sobre el Acceso con Google para obtener información sobre cómo usar el Acceso con Google en iOS.
- Agrega esquemas de URL personalizadas al proyecto de Xcode:
- Abre la configuración del proyecto: haz doble clic en el nombre del proyecto en la vista de árbol a la izquierda. Selecciona la app en la sección OBJETIVOS, haz clic en la pestaña Información y expande la sección URL Types (Tipos de URL).
- Haz clic en el botón + y agrega un esquema de URL para el ID de cliente invertido. A fin de obtener este valor, abre el archivo de configuración
y busca la claveGoogleService-Info.plist REVERSED_CLIENT_ID
. Copia el valor de esa clave y pégalo en el recuadro URL Schemes (Esquemas de URL) en la página de configuración. Deja los demás campos en blanco.Cuando termines, la configuración debería ser similar a la que se muestra a continuación (pero con los valores específicos de tu aplicación):
- Declara que el delegado de la app implementa el protocolo
GIDSignInDelegate
.Swift
EnAppDelegate.swift
:class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
Objective-C
EnAppDelegate.h
:@interface AppDelegate : UIResponder<UIApplicationDelegate, GIDSignInDelegate>
- En el método
application:didFinishLaunchingWithOptions:
del delegado de tu app, configura el objetoFirebaseApp
y el delegado de acceso.Swift
// Use Firebase library to configure APIs FirebaseApp.configure() GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID GIDSignIn.sharedInstance().delegate = self
Objective-C
// Use Firebase library to configure APIs [FIRApp configure]; [GIDSignIn sharedInstance].clientID = [FIRApp defaultApp].options.clientID; [GIDSignIn sharedInstance].delegate = self;
- Implementa el método
application:openURL:options:
del delegado de la app. Esto debería invocar el métodohandleURL
de la instanciaGIDSignIn
, que manejará correctamente la URL que reciba la aplicación al final del proceso de autenticación.Swift
@available(iOS 9.0, *) func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { return GIDSignIn.sharedInstance().handle(url) }
Objective-C
- (BOOL)application:(nonnull UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<NSString *, id> *)options { return [[GIDSignIn sharedInstance] handleURL:url]; }
Para que tu app funcione en iOS 8 y versiones anteriores, también deberás implementar el método obsoleto
application:openURL:sourceApplication:annotation:
.Swift
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { return GIDSignIn.sharedInstance().handle(url) }
Objective-C
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { return [[GIDSignIn sharedInstance] handleURL:url]; }
- En el delegado de la app, implementa el protocolo
GIDSignInDelegate
para administrar el acceso. Para ello, define los siguientes métodos:Objective-C
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error { // ... if (error == nil) { GIDAuthentication *authentication = user.authentication; FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken accessToken:authentication.accessToken]; // ... } else { // ... } } - (void)signIn:(GIDSignIn *)signIn didDisconnectWithUser:(GIDGoogleUser *)user withError:(NSError *)error { // Perform any operations when the user disconnects from app here. // ... }
Swift
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) { // ... if let error = error { // ... return } guard let authentication = user.authentication else { return } let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken) // ... } func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) { // Perform any operations when the user disconnects from app here. // ... }
- En el controlador de vista, anula el método
viewDidLoad
para configurar el controlador de vista de presentación del objetoGIDSignIn
y, de forma opcional, acceder de forma silenciosa siempre que sea posible.Objective-C
[GIDSignIn sharedInstance].presentingViewController = self; [[GIDSignIn sharedInstance] signIn];
Swift
GIDSignIn.sharedInstance()?.presentingViewController = self GIDSignIn.sharedInstance().signIn()
- Agrega un botón
GIDSignInButton
a tu diseño o archivo XIB, o crea una instancia de manera programática. Para agregar el botón a tu diseño o archivo XIB, agrega una vista y define su clase personalizada comoGIDSignInButton
. - Opcional: Si quieres personalizar el botón, puedes hacer lo siguiente:
Swift
- En el controlador de vista, declara el botón de acceso como una propiedad.
@IBOutlet weak var signInButton: GIDSignInButton!
- Conecta el botón a la propiedad
signInButton
que acabas de declarar. - Configura las propiedades del objeto GIDSignInButton para personalizar el botón.
Objective-C
- En el archivo de encabezado de tu controlador de vista, declara el botón de acceso como una propiedad.
@property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
- Conecta el botón a la propiedad
signInButton
que acabas de declarar. - Configura las propiedades del objeto GIDSignInButton para personalizar el botón.
- En el controlador de vista, declara el botón de acceso como una propiedad.
3. Autentica con Firebase
En el método signIn:didSignInForUser:withError:
, obtén un token de ID de Google y un token de acceso de Google del objeto GIDAuthentication
, y cámbialos por una credencial de Firebase:
Swift
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) { // ... if let error = error { // ... return } guard let authentication = user.authentication else { return } let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken) // ... }
Objective-C
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error { // ... if (error == nil) { GIDAuthentication *authentication = user.authentication; FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken accessToken:authentication.accessToken]; // ... } else { // ... } }
Por último, usa la credencial para autenticar con Firebase:
Swift
Auth.auth().signIn(with: credential) { (authResult, error) in if let error = error { let authError = error as NSError if (isMFAEnabled && authError.code == AuthErrorCode.secondFactorRequired.rawValue) { // The user is a multi-factor user. Second factor challenge is required. let resolver = authError.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver var displayNameString = "" for tmpFactorInfo in (resolver.hints) { displayNameString += tmpFactorInfo.displayName ?? "" displayNameString += " " } self.showTextInputPrompt(withMessage: "Select factor to sign in\n\(displayNameString)", completionBlock: { userPressedOK, displayName in var selectedHint: PhoneMultiFactorInfo? for tmpFactorInfo in resolver.hints { if (displayName == tmpFactorInfo.displayName) { selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo } } PhoneAuthProvider.provider().verifyPhoneNumber(with: selectedHint!, uiDelegate: nil, multiFactorSession: resolver.session) { verificationID, error in if error != nil { print("Multi factor start sign in failed. Error: \(error.debugDescription)") } else { self.showTextInputPrompt(withMessage: "Verification code for \(selectedHint?.displayName ?? "")", completionBlock: { userPressedOK, verificationCode in let credential: PhoneAuthCredential? = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!, verificationCode: verificationCode!) let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator.assertion(with: credential!) resolver.resolveSignIn(with: assertion!) { authResult, error in if error != nil { print("Multi factor finanlize sign in failed. Error: \(error.debugDescription)") } else { self.navigationController?.popViewController(animated: true) } } }) } } }) } else { self.showMessagePrompt(error.localizedDescription) return } // ... return } // User is signed in // ... }
Objective‑C
[[FIRAuth auth] signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (isMFAEnabled && error && error.code == FIRAuthErrorCodeSecondFactorRequired) { FIRMultiFactorResolver *resolver = error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey]; NSMutableString *displayNameString = [NSMutableString string]; for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) { [displayNameString appendString:tmpFactorInfo.displayName]; [displayNameString appendString:@" "]; } [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Select factor to sign in\n%@", displayNameString] completionBlock:^(BOOL userPressedOK, NSString *_Nullable displayName) { FIRPhoneMultiFactorInfo* selectedHint; for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) { if ([displayName isEqualToString:tmpFactorInfo.displayName]) { selectedHint = (FIRPhoneMultiFactorInfo *)tmpFactorInfo; } } [FIRPhoneAuthProvider.provider verifyPhoneNumberWithMultiFactorInfo:selectedHint UIDelegate:nil multiFactorSession:resolver.session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { if (error) { [self showMessagePrompt:error.localizedDescription]; } else { [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Verification code for %@", selectedHint.displayName] completionBlock:^(BOOL userPressedOK, NSString *_Nullable verificationCode) { FIRPhoneAuthCredential *credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID verificationCode:verificationCode]; FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential]; [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error) { [self showMessagePrompt:error.localizedDescription]; } else { NSLog(@"Multi factor finanlize sign in succeeded."); } }]; }]; } }]; }]; } else if (error) { // ... return; } // User successfully signed in. Get user data from the FIRUser object if (authResult == nil) { return; } FIRUser *user = authResult.user; // ... }];
Pasos siguientes
Cuando un usuario accede por primera vez, se crea una cuenta de usuario nueva y se la vincula con las credenciales (el nombre de usuario y la contraseña, el número de teléfono o la información del proveedor de autenticación) que el usuario utilizó para acceder. Esta cuenta nueva se almacena como parte de tu proyecto de Firebase y se puede usar para identificar a un usuario en todas las apps del proyecto, sin importar cómo acceda.
-
En tus apps, puedes obtener la información básica de perfil del usuario a partir del objeto
FIRUser
. Consulta Administra usuarios en Firebase. En tus reglas de seguridad de Firebase Realtime Database y Cloud Storage, puedes obtener el ID del usuario único que accedió a partir de la variable
auth
y usarlo para controlar a qué datos podrá acceder.
Para permitir que los usuarios accedan a la app con varios proveedores de autenticación, puedes vincular las credenciales de estos proveedores con una cuenta de usuario existente.
Para salir de la sesión de un usuario, llama a signOut:
.
Swift
let firebaseAuth = Auth.auth() do { try firebaseAuth.signOut() } catch let signOutError as NSError { print ("Error signing out: %@", signOutError) }
Objective‑C
NSError *signOutError; BOOL status = [[FIRAuth auth] signOut:&signOutError]; if (!status) { NSLog(@"Error signing out: %@", signOutError); return; }
Tal vez sea conveniente que agregues código de administración de errores para todos los errores de autenticación. Consulta Maneja errores.