/ kyokomi note / blog

Android Login with FirebaseUIをやってみた

June 7, 2020 [Android | Firebase]

FirebaseAuthを使ったLoginのcodelab。

1と2に分かれているが、まとめてやってしまっていいボリューム感だった。

対象のcodelab

このcodelabで学べること

FirebaseプロジェクトにAndroidを追加する

image-20200607165405000

証明書SHA-1の生成

$ keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android

FirebaseUIでloginして結果を受け取る

buttonクリック -> FirebaseAuthUIのActivityを呼び出し -> SingUp/SingInのonActivityResultで結果をもらう部分のコード。

AuthUIをbuildしたものをstartActivityForResultにわたすだけで組み込みがかなり簡単。

// MainFragment.kt

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    observeAuthenticationState()
   
    binding.authButton.setOnClickListener {
        // TODO call launchSignInFlow when authButton is clicked
        launchSignInFlow()
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    // TODO Listen to the result of the sign in process by filter for when
    //  SIGN_IN_REQUEST_CODE is passed back. Start by having log statements to know
    //  whether the user has signed in successfully
    if (requestCode == SIGN_IN_RESULT_CODE) {
        val response = IdpResponse.fromResultIntent(data)
        if (resultCode == Activity.RESULT_OK) {
            Log.i(
                TAG,
                "Successfully signed in user ${FirebaseAuth.getInstance().currentUser?.displayName}"
            )
        } else {
            Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
        }
    }
}
    
private fun launchSignInFlow() {
    // TODO Complete this function by allowing users to register and sign in with
    //  either their email address or Google account.
   
    val providers = arrayListOf(
        AuthUI.IdpConfig.EmailBuilder().build(),
        AuthUI.IdpConfig.GoogleBuilder().build()
    )
   
    startActivityForResult(
        AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAvailableProviders(providers)
            .build(),
        SIGN_IN_RESULT_CODE
    )
}

実行時のログ

2020-06-06 16:24:20.842 11649-11649/com.example.android.firebaseui_login_sample I/MainFragment: Successfully signed in user kyokomidev

実行してみた画面遷移

MainFragmentAuthUI(Provider選択)AuthUI(Emailログイン)

Firebaseのコンソール上でもuser登録されてるのを確認できる

Login状態の監視

LiveData継承してFirebaseAuth専用のLiveDataを作ってViewModelで参照する。

// FirebaseUserLiveData.kt

class FirebaseUserLiveData : LiveData<FirebaseUser?>() {
    private val firebaseAuth = FirebaseAuth.getInstance()

    private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
        value = firebaseAuth.currentUser
    }
    
    ...
}
// LoginViewModel.kt

var authenticationState = FirebaseUserLiveData().map { user ->
    if (user != null) {
        AuthenticationState.AUTHENTICATED
    } else {
        AuthenticationState.UNAUTHENTICATED
    }
}
// MainFragment.kt

private fun observeAuthenticationState() {
     val factToDisplay = viewModel.getFactToDisplay(requireContext())
     viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
         when (authenticationState) {
             LoginViewModel.AuthenticationState.AUTHENTICATED -> {
                 binding.authButton.text = getString(R.string.logout_button_text)
                 binding.authButton.setOnClickListener {
                     AuthUI.getInstance().signOut(requireContext())
                 }
                 binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
             }
             else -> {
                 binding.authButton.text = getString(R.string.login_button_text)
                 binding.authButton.setOnClickListener {
                     launchSignInFlow()
                 }
                 binding.welcomeText.text = factToDisplay
             }
         }
     })
 }

これで、Loginの状況によってUIが変化するようになる。

ログイン済み未ログイン

AuthUIおまけ

.setLogo(R.drawable.cooked_egg) とか足すと認証の画面をある程度カスタマイズできる。

他にもtheme設定など色々あるので、自前で作らなくて済みそう。

AuthUI.getInstance()
	.createSignInIntentBuilder()
	.setLogo(R.drawable.cooked_egg) // ロゴを設定
	.setAvailableProviders(providers)
	.build()

navigationで設定したactionをコードから呼び出すことができる。

image-20200607171226711

<fragment
    android:id="@+id/accountFragment"
    android:name="com.unity.mynativeapp.ui.account.AccountFragment"
    android:label="AccountFragment"
    tools:layout="@layout/fragment_account">
    <action
      android:id="@+id/action_accountFragment_to_settingsFragment"
      app:destination="@id/settingsFragment" />
  </fragment>
binding.settingsBtn.setOnClickListener {
	val action = AccountFragmentDirections.actionAccountFragmentToSettingsFragment()
	findNavController().navigate(action)
}

まとめ

last modified August 29, 2020

👋 Related posts in the codelab series...