ActivityResultContractとViewModelを使ってFirebase Auth×Googleログインをスッキリ書く

## はじめに
AACのViewModelを用いた場合、onActivityResultが絡んだコードを書くときに辛みが発生していましたが、[前回の記事](https://qiita.com/masaibar/items/0cd52d017119171b1ed9)を基に、Firebase AuthでのGoogleログインの処理を書いてみたら思いの外スッキリしたので記録を残しておきます。
なお、本記事ではFirebase Auth×Googleログインに関する基本的な解説はしません。

全体のソースコードはこちらです：https://github.com/masaibar/SimpleGoogleLogin


## 実装
詳細な差分は[こちら](https://github.com/masaibar/SimpleGoogleLogin/pull/1)を御覧ください。

### app/build.gradle
安定版である1.1.0には`ActivityResultContract`が含まれていないので注意して下さい。

```gradle:app/build.gradle
    implementation "androidx.activity:activity-ktx:1.2.0-alpha06"
//      implementation "androidx.fragment:fragment-ktx:1.3.0-alpha06" Fragmentの場合
```

### MainActivity.kt
ログインに関する処理を全てViewModel側に閉じ込めることが出来るようになり、Activity側に`onActivityResult`を書かなくて良くなったのでボタンのリスナーを呼び出すだけになりました。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    private val viewModel: MainViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sign_in_button.setOnClickListener {
            viewModel.onClickSignIn(this)
        }
    }
}

```

### MainViewModel.kt
`onClickSignIn`で受け取るのは`FragmentActivity`型にしないと`activityResultRegistry`が参照できないので気をつけましょう。

```kotlin:MainViewModel.kt
class MainViewModel : ViewModel() {

    private val firebaseAuth: FirebaseAuth = FirebaseAuth.getInstance()

    fun onClickSignIn(activity: FragmentActivity) {
        val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(activity.getString(R.string.default_web_client_id))
            .requestEmail()
            .build()
        val googleSignInClient = GoogleSignIn.getClient(
            activity,
            googleSignInOptions
        )

        activity.activityResultRegistry.register(
            "key",
            ActivityResultContracts.StartActivityForResult()
        ) { activityResult ->
            if (activityResult.data == null) {
                return@register
            }

            GoogleSignIn.getSignedInAccountFromIntent(activityResult.data)
                .addOnCompleteListener { task ->
                    if (task.isSuccessful) {
                        task.getResult(ApiException::class.java)?.let {
                            firebaseAuthWithGoogle(it)
                        }
                    }
                }
        }.launch(googleSignInClient.signInIntent)
    }

    private fun firebaseAuthWithGoogle(account: GoogleSignInAccount) {
        firebaseAuth.signInWithCredential(
            GoogleAuthProvider.getCredential(
                account.idToken,
                null
            )
        ).addOnSuccessListener {
            Log.d("Login Succeeded!!!", "${it.user?.uid}")
        }
    }
}
```

## おわりに
ViewModel側にログインにまつわる処理を閉じ込めることが出来たおかげで、UI側をシンプルなコードに保つことが出来るようになりました。
例えば[この記事](https://medium.com/firebase-tips-tricks/how-to-create-a-clean-firebase-authentication-using-mvvm-37f9b8eb7336)のように、MVVMとFirebase Authの実装方法は様々な議論がされてきていると思いますがActivityResultContractを利用することによって新たな可能性が生まれたと思います。

全体のソースコードはこちらです（再掲）：https://github.com/masaibar/SimpleGoogleLogin