Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

使用 FirebaseUI 轻松向 Android 应用添加登录机制

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

  • 多提供方 - 支持电子邮件地址/密码、电子邮件链接、电话身份验证、Google 登录、Facebook 登录、Twitter 登录和 GitHub 登录的登录流程。
  • 帐号管理 - 用于处理帐号管理任务(如帐号创建和密码重置)的流程。
  • 帐号关联 - 用于将各种身份提供方安全地关联到用户帐号的流程。
  • 匿名用户升级 - 用于安全升级匿名用户的流程。
  • 自定义主题背景 - 对 FirebaseUI 的外观进行自定义,使其与您的应用相匹配。另外,FirebaseUI 是开源的,因此您可以创建项目分支 (fork),并根据您的需求对其进行定制。
  • Smart Lock(密码专用)- 与 Smart Lock(密码专用)自动集成,因而能够实现快速跨设备登录。

准备工作

  1. 将 Firebase 添加到您的 Android 项目(如果尚未添加)。

  2. 将 FirebaseUI 的依赖项添加到您的应用级 build.gradle 文件。如果您希望支持使用 Facebook 或 Twitter 帐号登录,还需要添加 Facebook SDK 和 Twitter SDK:

    dependencies {
        // ...
    
        implementation 'com.firebaseui:firebase-ui-auth:7.2.0'
    
        // Required only if Facebook login support is required
        // Find the latest Facebook SDK releases here: https://goo.gl/Ce5L94
        implementation 'com.facebook.android:facebook-android-sdk:8.x'
    }
    

    FirebaseUI Auth SDK 需要使用 Firebase SDK 和 Google Play 服务 SDK 提供的传递依赖项。

  3. Firebase 控制台中,打开身份验证部分并启用您希望支持的登录方法。有些登录方法需要额外的信息,这些信息通常可在相应服务的开发者控制台中找到。

  4. 如果您支持 Google 登录机制但尚未指定应用的 SHA-1 指纹,请在 Firebase 控制台的设置页面中进行此操作。如需详细了解如何获取您的应用的 SHA-1 指纹,请参阅对客户端进行身份验证

  5. 如果您支持使用 Facebook 或 Twitter 帐号登录,请在 strings.xml 中添加字符串资源以指定每个提供方所需的标识信息:

    
    <resources>
      <!-- Facebook application ID and custom URL scheme (app ID prefixed by 'fb'). -->
      <string name="facebook_application_id" translatable="false">YOUR_APP_ID</string>
      <string name="facebook_login_protocol_scheme" translatable="false">fbYOUR_APP_ID</string>
    </resources>
    

登录

创建一个 ActivityResultLauncher,它可为 FirebaseUI Activity 结果合约注册回调:

Java

// See: https://developer.android.com/training/basics/intents/result
private final ActivityResultLauncher<Intent> signInLauncher = registerForActivityResult(
        new FirebaseAuthUIActivityResultContract(),
        new ActivityResultCallback<FirebaseAuthUIAuthenticationResult>() {
            @Override
            public void onActivityResult(FirebaseAuthUIAuthenticationResult result) {
                onSignInResult(result);
            }
        }
);

Kotlin+KTX

// See: https://developer.android.com/training/basics/intents/result
private val signInLauncher = registerForActivityResult(
        FirebaseAuthUIActivityResultContract()
) { res ->
    this.onSignInResult(res)
}

如需启动 FirebaseUI 登录流程,请使用您偏好的登录方法创建登录 Intent:

Java

// Choose authentication providers
List<AuthUI.IdpConfig> providers = Arrays.asList(
        new AuthUI.IdpConfig.EmailBuilder().build(),
        new AuthUI.IdpConfig.PhoneBuilder().build(),
        new AuthUI.IdpConfig.GoogleBuilder().build(),
        new AuthUI.IdpConfig.FacebookBuilder().build(),
        new AuthUI.IdpConfig.TwitterBuilder().build());

// Create and launch sign-in intent
Intent signInIntent = AuthUI.getInstance()
        .createSignInIntentBuilder()
        .setAvailableProviders(providers)
        .build();
signInLauncher.launch(signInIntent);

Kotlin+KTX

// Choose authentication providers
val providers = arrayListOf(
        AuthUI.IdpConfig.EmailBuilder().build(),
        AuthUI.IdpConfig.PhoneBuilder().build(),
        AuthUI.IdpConfig.GoogleBuilder().build(),
        AuthUI.IdpConfig.FacebookBuilder().build(),
        AuthUI.IdpConfig.TwitterBuilder().build())

// Create and launch sign-in intent
val signInIntent = AuthUI.getInstance()
        .createSignInIntentBuilder()
        .setAvailableProviders(providers)
        .build()
signInLauncher.launch(signInIntent)

登录流程完成后,您会在 onSignInResult 中收到结果:

Java

private void onSignInResult(FirebaseAuthUIAuthenticationResult result) {
    IdpResponse response = result.getIdpResponse();
    if (result.getResultCode() == RESULT_OK) {
        // Successfully signed in
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        // ...
    } else {
        // Sign in failed. If response is null the user canceled the
        // sign-in flow using the back button. Otherwise check
        // response.getError().getErrorCode() and handle the error.
        // ...
    }
}

Kotlin+KTX

private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) {
    val response = result.idpResponse
    if (result.resultCode == RESULT_OK) {
        // Successfully signed in
        val user = FirebaseAuth.getInstance().currentUser
        // ...
    } else {
        // Sign in failed. If response is null the user canceled the
        // sign-in flow using the back button. Otherwise check
        // response.getError().getErrorCode() and handle the error.
        // ...
    }
}

设置登录方法

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

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

  3. 您还必须启用 Firebase Dynamic Links 才能使用电子邮件链接登录。在 Firebase 控制台的导航栏中,点击吸引下的 Dynamic Links。点击开始使用,并添加一个网域。您在此处选择的网域将反映在发送给用户的电子邮件链接中。

  4. 您可以对 EmailBuilder 实例调用 enableEmailLinkSignIn,从而在 FirebaseUI 中启用电子邮件链接登录。您还需要提供一个有效的 ActionCodeSettings 对象,并将 setHandleCodeInApp 设置为 true。此外,您需要将传递给 setUrl 的网址列入白名单,此操作可通过在 Firebase 控制台中依次点击 "Authentication" ->“登录方法”->“已获授权的网域”来完成。

    Java

    ActionCodeSettings actionCodeSettings = ActionCodeSettings.newBuilder()
            .setAndroidPackageName(
                    /* yourPackageName= */ "...",
                    /* installIfNotAvailable= */ true,
                    /* minimumVersion= */ null)
            .setHandleCodeInApp(true) // This must be set to true
            .setUrl("https://google.com") // This URL needs to be whitelisted
            .build();
    
    List<AuthUI.IdpConfig> providers = Arrays.asList(
            new AuthUI.IdpConfig.EmailBuilder()
                    .enableEmailLinkSignIn()
                    .setActionCodeSettings(actionCodeSettings)
                    .build()
    );
    Intent signInIntent = AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAvailableProviders(providers)
            .build();
    signInLauncher.launch(signInIntent);

    Kotlin+KTX

    val actionCodeSettings = ActionCodeSettings.newBuilder()
            .setAndroidPackageName( /* yourPackageName= */
                    "...",  /* installIfNotAvailable= */
                    true,  /* minimumVersion= */
                    null)
            .setHandleCodeInApp(true) // This must be set to true
            .setUrl("https://google.com") // This URL needs to be whitelisted
            .build()
    
    val providers = listOf(
            EmailBuilder()
                    .enableEmailLinkSignIn()
                    .setActionCodeSettings(actionCodeSettings)
                    .build()
    )
    val signInIntent = AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAvailableProviders(providers)
            .build()
    signInLauncher.launch(signInIntent)
  5. 如果您想要捕获特定活动中的链接,请按照此处概述的步骤操作。否则,链接将重定向至您的启动器 Activity。

  6. 捕获深层链接后,您需要通过调用相关方法以确认我们是否可以为您处理。如果我们可以,您需要通过 setEmailLink 将其传递给我们。

    Java

    if (AuthUI.canHandleIntent(getIntent())) {
        if (getIntent().getExtras() == null) {
            return;
        }
        String link = getIntent().getExtras().getString(ExtraConstants.EMAIL_LINK_SIGN_IN);
        if (link != null) {
            Intent signInIntent = AuthUI.getInstance()
                    .createSignInIntentBuilder()
                    .setEmailLink(link)
                    .setAvailableProviders(providers)
                    .build();
            signInLauncher.launch(signInIntent);
        }
    }

    Kotlin+KTX

    if (AuthUI.canHandleIntent(intent)) {
        val extras = intent.extras ?: return
        val link = extras.getString(ExtraConstants.EMAIL_LINK_SIGN_IN)
        if (link != null) {
            val signInIntent = AuthUI.getInstance()
                    .createSignInIntentBuilder()
                    .setEmailLink(link)
                    .setAvailableProviders(providers)
                    .build()
            signInLauncher.launch(signInIntent)
        }
    }
  7. 可选:支持跨设备电子邮件链接登录机制,这意味着可使用通过 Android 应用发送的链接登录您的 Web 或 iOS 应用。默认情况下,跨设备支持功能处于启用状态。您可以停用此功能,只需对 EmailBuilder 实例调用 setForceSameDevice 即可。

    如需了解详情,请参阅 FirebaseUI-WebFirebaseUI-iOS

退出帐号

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

Java

AuthUI.getInstance()
        .signOut(this)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            public void onComplete(@NonNull Task<Void> task) {
                // ...
            }
        });

Kotlin+KTX

AuthUI.getInstance()
        .signOut(this)
        .addOnCompleteListener {
            // ...
        }

您也可以完全删除用户的帐号:

Java

AuthUI.getInstance()
        .delete(this)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // ...
            }
        });

Kotlin+KTX

AuthUI.getInstance()
        .delete(this)
        .addOnCompleteListener {
            // ...
        }

自定义

默认情况下,FirebaseUI 使用 AppCompat 设置主题背景,这意味着它会自动采用应用的配色方案。如需进一步自定义,您可以将主题背景和徽标传递给登录 Intent 构建器:

Java

Intent signInIntent = AuthUI.getInstance()
        .createSignInIntentBuilder()
        .setAvailableProviders(providers)
        .setLogo(R.drawable.my_great_logo)      // Set logo drawable
        .setTheme(R.style.MySuperAppTheme)      // Set theme
        .build();
signInLauncher.launch(signInIntent);

Kotlin+KTX

val signInIntent = AuthUI.getInstance()
        .createSignInIntentBuilder()
        .setAvailableProviders(providers)
        .setLogo(R.drawable.my_great_logo) // Set logo drawable
        .setTheme(R.style.MySuperAppTheme) // Set theme
        .build()
signInLauncher.launch(signInIntent)

您还可以设置自定义的隐私权政策和服务条款:

Java

Intent signInIntent = AuthUI.getInstance()
        .createSignInIntentBuilder()
        .setAvailableProviders(providers)
        .setTosAndPrivacyPolicyUrls(
                "https://example.com/terms.html",
                "https://example.com/privacy.html")
        .build();
signInLauncher.launch(signInIntent);

Kotlin+KTX

val signInIntent = AuthUI.getInstance()
        .createSignInIntentBuilder()
        .setAvailableProviders(providers)
        .setTosAndPrivacyPolicyUrls(
                "https://example.com/terms.html",
                "https://example.com/privacy.html")
        .build()
signInLauncher.launch(signInIntent)

后续步骤

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