使用 FirebaseUI 轻松向 iOS 应用添加登录服务

FirebaseUI 是以 Firebase Authentication SDK 为基础构建的库,提供适合在您应用中使用的普适性界面流程。FirebaseUI 具有以下优势:

  • 多提供方:支持电子邮件地址/密码、电子邮件链接、电话身份验证、Google 登录、Facebook 登录和 Twitter 登录的登录流程。
  • 帐号管理:用于处理帐号管理任务(如帐号创建和密码重置)的流程。
  • 匿名帐号关联:用于自动将匿名帐号关联到身份提供方的流程。
  • 可自定义:自定义 FirebaseUI 的外观以便与您的应用相匹配。另外,FirebaseUI 是开源的,因此您可以复刻 (fork) 项目,并根据您的需求对其进行定制。

准备工作

  1. 将 Firebase 添加到您的 Apple 项目

  2. 将 FirebaseUI 添加到您的 Podfile:

    pod 'FirebaseUI'
    

    根据您的个人喜好,您可以只添加 Auth 组件及您想要使用的提供方:

    pod 'FirebaseUI/Auth'
    
    pod 'FirebaseUI/Google'
    pod 'FirebaseUI/Facebook'
    pod 'FirebaseUI/OAuth' # Used for Sign in with Apple, Twitter, etc
    pod 'FirebaseUI/Phone'
    
  3. 如果您尚未将应用关联至您的 Firebase 项目,请从 Firebase 控制台执行此操作。

设置登录方法

您必须先启用并配置您希望支持的登录方法,然后用户才能通过 Firebase 登录。

电子邮件地址和密码

Firebase 控制台中,打开 Authentication 部分并启用电子邮件地址和密码身份验证。

  1. Firebase 控制台中,打开 Authentication 部分。在 Sign in method(登录方法)标签页中,启用电子邮件地址/密码提供方。请注意,必须启用电子邮件地址/密码登录才能使用电子邮件链接登录流程。

  2. 在同一部分中,启用电子邮件链接(无密码登录)登录方法,然后点击保存

  3. 您可以初始化一个 FUIEmailAuth 实例并通过 FIREmailLinkAuthSignInMethod 来启用电子邮件链接登录。您还需要提供一个有效的 FIRActionCodeSettings 对象,并将 handleCodeInApp 设置为 true。

Swift

var actionCodeSettings = ActionCodeSettings()
actionCodeSettings.url = URL(string: "https://example.appspot.com")
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setAndroidPackageName("com.firebase.example", installIfNotAvailable: false, minimumVersion: "12")

let provider = FUIEmailAuth(authUI: FUIAuth.defaultAuthUI()!,
                            signInMethod: FIREmailLinkAuthSignInMethod,
                            forceSameDevice: false,
                            allowNewEmailAccounts: true,
                            actionCodeSetting: actionCodeSettings)

Objective-C

FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
actionCodeSettings.URL = [NSURL URLWithString:@"https://example.appspot.com"];
actionCodeSettings.handleCodeInApp = YES;
[actionCodeSettings setAndroidPackageName:@"com.firebase.example"
                    installIfNotAvailable:NO
                           minimumVersion:@"12"];

id<FUIAuthProvider> provider = [[FUIEmailAuth alloc] initWithAuthUI:[FUIAuth defaultAuthUI]
                                                       signInMethod:FIREmailLinkAuthSignInMethod
                                                    forceSameDevice:NO
                                              allowNewEmailAccounts:YES
                                                  actionCodeSetting:actionCodeSettings];
  1. 此外,您需要将您传递给初始化程序的网址列入白名单。具体方法是在 Firebase 控制台中,打开 Authentication 部分。在 Sign in method(登录方法)标签页上,在已获授权的网域下添加该网址。

  2. 捕获深层链接后,您需要将其传递至身份验证界面,以便进行处理。

Swift

FUIAuth.defaultAuthUI()!.handleOpen(url, sourceApplication: sourceApplication)

Objective-C

[[FUIAuth defaultAuthUI] handleOpenURL:url sourceApplication:sourceApplication];
  1. FirebaseUI-iOS 中的电子邮件链接登录方法与 FirebaseUI-AndroidFirebaseUI-web 兼容(在这种情况下,一个从 FirebaseUI-Android 启动该流程的用户可以打开链接并使用 FirebaseUI-web 完成登录)。对于反向流程也是如此。

Apple

  1. 按照 Firebase 使用 Apple 帐号登录指南中的准备工作符合 Apple 匿名数据要求部分中的说明进行操作。

  2. 向您的权限 (entitlements) 文件添加“使用 Apple 帐号登录”功能。

  3. 初始化针对“使用 Apple 帐号登录”功能配置的 OAuth 提供方实例:

    Swift

    provider = FUIOAuth.appleAuthProvider()
    

    Objective-C

    FUIOAuth *provider = [FUIOAuth appleAuthProvider];
    

Google

  1. Firebase 控制台中,打开 Authentication 部分并启用 Google 登录。

  2. 重新下载项目 GoogleService-Info.plist 文件的副本,并将其复制到您的 Xcode 项目。用这个最新版本的文件覆盖任何现有的旧版本。(请参阅将 Firebase 添加到您的 iOS 项目。)

  3. 在您的 Xcode 项目中,将您的倒序客户端 ID 添加为网址方案。您可以在 GoogleService-Info.plist 文件中找到这个值。

    Facebook

  4. 按照 Facebook 的使用入门页面来设置 Facebook 登录 SDK。

  5. Firebase 控制台中,打开 Authentication 部分并启用 Facebook 登录服务。要启用 Facebook 登录服务,您必须提供您的 Facebook 应用 ID (App ID) 和应用密钥 (App Secret),这些信息可在 Facebook 开发者控制台中找到。

  6. 在您的 Xcode 项目中,依次点击项目设置 > 功能,然后在相应界面中启用密钥链共享。

  7. 在您的 Xcode 项目中,将 fbFACEBOOK_APP_ID 添加为网址方案。

  8. 将您的 Facebook 应用 ID 和显示名添加至 Info.plist 文件中:

    FacebookAppID FACEBOOK_APP_ID(例如 1234567890
    FacebookDisplayName 您的应用的名称
  9. 初始化 Facebook 提供方实例:

    Swift

    provider = FUIFacebookAuth(authUI: FUIAuth.defaultAuthUI())
    

    Objective-C

    FUIFacebookAuth *provider = [[FUIFacebookAuth alloc] initWithAuthUI:[FUIAuth defaultAuthUI]];
    

  10. 如果您要使用 Facebook 受限登录,请设置 FUIFacebookAuth 实例的 useLimitedLogin 属性。

    Swift

    provider.useLimitedLogin = true
    

    Objective-C

    provider.useLimitedLogin = YES;
    

Twitter

  1. Firebase 控制台中,打开 Authentication 部分并启用 Twitter 登录服务。如需启用 Twitter 登录服务,您必须提供您的 Twitter API 使用方密钥和密文,这些信息可在 Twitter Application Management 控制台中找到。

  2. 初始化为 Twitter 登录服务配置的 OAuth 提供方实例:

    Swift

    provider = FUIOAuth.twitterAuthProvider()
    

    Objective-C

    FUIOAuth *provider = [FUIOAuth twitterAuthProvider];
    

电话号码

  1. Firebase 控制台中,打开 Authentication 部分并启用电话号码登录服务。

  2. Firebase 必须要能验证电话号码登录请求是否来自于您的应用。您可以使用 APNs 通知来实现这一目的。如需了解详情,请参阅启用应用验证

    如需启用 APNs 通知以用于 Firebase Authentication,请执行以下操作:

    1. 在 Xcode 中为您的项目启用推送通知

    2. 将您的 APNs 身份验证密钥上传到 Firebase。如果您还没有 APNs 身份验证密钥,请务必在 Apple Developer Member Center 内创建一个。

      1. 在 Firebase 控制台中,在您的项目内依次选择齿轮图标 > 项目设置 > Cloud Messaging 标签页。

      2. iOS 应用配置下的 APNs 身份验证密钥中,点击上传按钮。

      3. 转到您保存密钥的位置,选择该密钥,然后点击打开。添加该密钥的 ID(可在 Apple Developer Member Center 中找到),然后点击上传

      如果您已有 APNs 证书,可以改为上传该证书。

  3. 如果设备无法接收 APNs 通知,Firebase 会使用 reCAPTCHA 来验证请求。

    如需启用 reCAPTCHA 验证,请在 Xcode 中执行以下操作:

    1. 打开您的项目配置:在左侧的树状视图中双击项目名称。在目标部分中选择您的应用,然后选择信息标签页,并展开网址类型部分。
    2. 点击 + 按钮,然后将经过编码的应用 ID 添加为网址方案。您可以打开 Firebase 控制台的常规设置页面,在您的 iOS 应用部分找到经过编码的应用 ID。请将其他字段留空。

      完成上述操作后,您的配置应显示如下(但其中的值应替换为您的应用的值):

      Xcode 自定义网址方案设置界面的屏幕截图
  4. 可选:Firebase 使用方法调配 (method swizzling) 自动获取您的应用的 APNs 令牌,处理 Firebase 发送给应用的静默推送通知,并自动拦截在验证期间来自 reCAPTCHA 验证页面的自定义方案重定向。

    如果您不想使用调配,请参阅 Firebase SDK 身份验证文档中的附录:使用电话登录而不调配

登录

要启动 FirebaseUI 登录流程,首先应初始化 FirebaseUI:

Swift

import FirebaseAuthUI

/* ... */

FirebaseApp.configure()
let authUI = FUIAuth.defaultAuthUI()
// You need to adopt a FUIAuthDelegate protocol to receive callback
authUI.delegate = self

Objective-C

@import FirebaseAuthUI;

...

[FIRApp configure];
FUIAuth *authUI = [FUIAuth defaultAuthUI];
// You need to adopt a FUIAuthDelegate protocol to receive callback
authUI.delegate = self;

然后,配置 FirebaseUI 以使用您希望支持的登录方法:

Swift

import FirebaseAuthUI
import FirebaseFacebookAuthUI
import FirebaseGoogleAuthUI
import FirebaseOAuthUI
import FirebasePhoneAuthUI

let providers: [FUIAuthProvider] = [
  FUIGoogleAuth(),
  FUIFacebookAuth(),
  FUITwitterAuth(),
  FUIPhoneAuth(authUI:FUIAuth.defaultAuthUI()),
]
self.authUI.providers = providers

Objective-C

@import FirebaseAuthUI;
@import FirebaseFacebookAuthUI;
@import FirebaseGoogleAuthUI;
@import FirebaseOAuthUI;
@import FirebasePhoneAuthUI;

...

NSArray<id<FUIAuthProvider>> *providers = @[
  [[FUIGoogleAuth alloc] init],
  [[FUIFacebookAuth alloc] init],
  [[FUITwitterAuth alloc] init],
  [[FUIPhoneAuth alloc] initWithAuthUI:[FUIAuth defaultAuthUI]]
];
_authUI.providers = providers;

如果您已启用 Google 或 Facebook 登录,请实现一个处理程序来处理 Google 和 Facebook 注册流程的结果:

Swift

func application(_ app: UIApplication, open url: URL,
    options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
  let sourceApplication = options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String?
  if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false {
    return true
  }
  // other URL handling goes here.
  return false
}

Objective-C

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary *)options {
  NSString *sourceApplication = options[UIApplicationOpenURLOptionsSourceApplicationKey];
  return [[FUIAuth defaultAuthUI] handleOpenURL:url sourceApplication:sourceApplication];
}

最后,从 FUIAuth 获取一个 AuthViewController 的实例。然后,您可以将该实例作为应用的第一个视图控制器呈现,或者从应用中的其他视图控制器呈现该实例。

Swift

要获取登录方法选择器,请使用以下代码:

let authViewController = authUI.authViewController()

如果您只使用电话号码登录方法,可以改为直接显示电话号码登录视图:

let phoneProvider = FUIAuth.defaultAuthUI().providers.first as! FUIPhoneAuth
phoneProvider.signIn(withPresenting: currentlyVisibleController, phoneNumber: nil)

Objective-C

要获取登录方法选择器,请使用以下代码:

UINavigationController *authViewController = [authUI authViewController];

如果您只使用电话号码登录方法,可以改为直接显示电话号码登录视图:

FUIPhoneAuth *phoneProvider = [FUIAuth defaultAuthUI].providers.firstObject;
[phoneProvider signInWithPresentingViewController:currentlyVisibleController phoneNumber:nil];

在呈现身份验证视图并且用户成功登录后,系统会将结果返回给 didSignInWithUser:error: 方法中的 FirebaseUI 身份验证委托:

Swift

func authUI(_ authUI: FUIAuth, didSignInWith user: FIRUser?, error: Error?) {
  // handle user and error as necessary
}

Objective-C

   - (void)authUI:(FUIAuth *)authUI
didSignInWithUser:(nullable FIRUser *)user
            error:(nullable NSError *)error {
  // Implement this method to handle signed in user or error if any.
}

退出帐号

FirebaseUI 提供了方便的方法来让用户退出 Firebase Authentication 以及所有社交身份提供方帐号:

Swift

authUI.signOut()

Objective-C

[authUI signOut];

自定义

您可以设置 FirebaseUI 视图控制器的子类,然后在 FUIAuth 的委托方法中指定这些子类,以自定义登录屏幕:

Swift

func authPickerViewController(forAuthUI authUI: FUIAuth) -> FUIAuthPickerViewController {
  return FUICustomAuthPickerViewController(nibName: "FUICustomAuthPickerViewController",
                                           bundle: Bundle.main,
                                           authUI: authUI)
}

func emailEntryViewController(forAuthUI authUI: FUIAuth) -> FUIEmailEntryViewController {
  return FUICustomEmailEntryViewController(nibName: "FUICustomEmailEntryViewController",
                                           bundle: Bundle.main,
                                           authUI: authUI)
}

func passwordRecoveryViewController(forAuthUI authUI: FUIAuth, email: String) -> FUIPasswordRecoveryViewController {
  return FUICustomPasswordRecoveryViewController(nibName: "FUICustomPasswordRecoveryViewController",
                                                 bundle: Bundle.main,
                                                 authUI: authUI,
                                                 email: email)
}

func passwordSignInViewController(forAuthUI authUI: FUIAuth, email: String) -> FUIPasswordSignInViewController {
  return FUICustomPasswordSignInViewController(nibName: "FUICustomPasswordSignInViewController",
                                               bundle: Bundle.main,
                                               authUI: authUI,
                                               email: email)
}

func passwordSignUpViewController(forAuthUI authUI: FUIAuth, email: String) -> FUIPasswordSignUpViewController {
  return FUICustomPasswordSignUpViewController(nibName: "FUICustomPasswordSignUpViewController",
                                               bundle: Bundle.main,
                                               authUI: authUI,
                                               email: email)
}

func passwordVerificationViewController(forAuthUI authUI: FUIAuth, email: String, newCredential: AuthCredential) -> FUIPasswordVerificationViewController {
  return FUICustomPasswordVerificationViewController(nibName: "FUICustomPasswordVerificationViewController",
                                                     bundle: Bundle.main,
                                                     authUI: authUI,
                                                     email: email,
                                                     newCredential: newCredential)
}

Objective-C

- (FUIAuthPickerViewController *)authPickerViewControllerForAuthUI:(FUIAuth *)authUI {
  return [[FUICustomAuthPickerViewController alloc] initWithNibName:@"FUICustomAuthPickerViewController"
                                                             bundle:[NSBundle mainBundle]
                                                             authUI:authUI];
}

- (FUIEmailEntryViewController *)emailEntryViewControllerForAuthUI:(FUIAuth *)authUI {
  return [[FUICustomEmailEntryViewController alloc] initWithNibName:@"FUICustomEmailEntryViewController"
                                                             bundle:[NSBundle mainBundle]
                                                             authUI:authUI];

}

- (FUIPasswordSignInViewController *)passwordSignInViewControllerForAuthUI:(FUIAuth *)authUI
                                                                     email:(NSString *)email {
  return [[FUICustomPasswordSignInViewController alloc] initWithNibName:@"FUICustomPasswordSignInViewController"
                                                                 bundle:[NSBundle mainBundle]
                                                                 authUI:authUI
                                                                  email:email];

}

- (FUIPasswordSignUpViewController *)passwordSignUpViewControllerForAuthUI:(FUIAuth *)authUI
                                                                     email:(NSString *)email {
  return [[FUICustomPasswordSignUpViewController alloc] initWithNibName:@"FUICustomPasswordSignUpViewController"
                                                                 bundle:[NSBundle mainBundle]
                                                                 authUI:authUI
                                                                  email:email];

}

- (FUIPasswordRecoveryViewController *)passwordRecoveryViewControllerForAuthUI:(FUIAuth *)authUI
                                                                         email:(NSString *)email {
  return [[FUICustomPasswordRecoveryViewController alloc] initWithNibName:@"FUICustomPasswordRecoveryViewController"
                                                                   bundle:[NSBundle mainBundle]
                                                                   authUI:authUI
                                                                    email:email];

}

- (FUIPasswordVerificationViewController *)passwordVerificationViewControllerForAuthUI:(FUIAuth *)authUI
                                                                                 email:(NSString *)email
                                                                         newCredential:(FIRAuthCredential *)newCredential {
  return [[FUICustomPasswordVerificationViewController alloc] initWithNibName:@"FUICustomPasswordVerificationViewController"
                                                                       bundle:[NSBundle mainBundle]
                                                                       authUI:authUI
                                                                        email:email
                                                                newCredential:newCredential];
}

您可以自定义指向应用服务条款的网址,该网址的链接会显示在帐号创建屏幕上:

Swift

let kFirebaseTermsOfService = URL(string: "https://example.com/terms")!
authUI.tosurl = kFirebaseTermsOfService

Objective-C

authUI.TOSURL = [NSURL URLWithString:@"https://example.com/terms"];

最后,您可以通过指定自定义 bundle 的方式来自定义向用户显示的消息和提示:

Swift

authUI.customStringsBundle = NSBundle.mainBundle() // Or any custom bundle.

Objective-C

authUI.customStringsBundle = [NSBundle mainBundle]; // Or any custom bundle.

后续步骤

  • 如需详细了解如何使用和自定义 FirebaseUI,请参阅 GitHub 上的 README 文件。
  • 如果您发现 FirebaseUI 中存在问题并希望提交报告,请使用 GitHub 问题跟踪器