【Android&Firebase】Googleログイン実装のDeprecated箇所をリファクタリングしてみた

# はじめに

皆さん、ごきげんよう！れぶです！
2回目のQiitaへの投稿になります。新年早々どこにも外出せずに執筆していきます。

今回の記事は、Firebaseを用いてAndroidアプリへGoogleログイン機能を実装することに関した内容になります。具体的には、Firebaseの公式ドキュメントに掲載されているコードの中で、Deprecated箇所（startActivityForResultとonActivityResult）があるので、リファクタリングしていきます。Googleログイン機能のリファクタリング実装が書かれた記事はあまりないと感じたので、自身がJavaで書いたコードをもとに紹介します。

それでは、参りましょう！！

# この記事の対象者

* 今後Firebase Authenticationを用いて、AndroidアプリにGoogleログイン機能を実装したい方
* 既にGoogleログイン機能を実装済みだけど、Deprecated箇所のリファクタリングが知りたい方

# 開発環境

* Mac
* Android Studio(4.1.2)
* Firebase(29.0.2)
* Java(8)

※ Firebaseの概要を知りたい方は、[この記事](https://career.levtech.jp/guide/knowhow/article/386/)を参考にしてみてください。

# 背景

[公式ドキュメント](https://firebase.google.cn/docs/auth/android/google-signin?hl=ja)では、Googleサインイン画面をstartActivityForResultで呼び出し、その結果をonActivityResultで取得する実装が掲載されています。

しかし、2020年4月29日でstartActivityForResultとonActivityResultはDeprecated（非推奨）となりました。詳しくは[こちら](https://developer.android.com/jetpack/androidx/releases/activity#1.2.0-alpha04)をご覧ください。

よって、このstartActivityForResultとonActivityResultの箇所をリファクタリングしていきます。
Deprecatedになると、打ち消し線(~~こんな感じ~~)が出てくるので、違和感しかないですよね。やっていきましょう。

# 実装方法

`ActivityResultLauncher`を使用した実装をします。Googleからは、この`Activity Result API`を使用することが推奨されているようです。

## リファクタリング前

[公式ドキュメント](https://firebase.google.cn/docs/auth/android/google-signin?hl=ja)より、該当箇所を引用しています。

あるイベント（ボタンが選択されたなど）をきっかけにsignInメソッドが呼ばれると、Googleサインイン画面をstartActivityForResultで呼び出し、起動させます。Googleサインイン画面から戻ってきた時に、結果をonActivityResultで取得しています。

```GoogleSignInActivity.java
private void signIn() {
    Intent signInIntent = mGoogleSignInClient.getSignInIntent();
    startActivityForResult(signInIntent, RC_SIGN_IN);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
    if (requestCode == RC_SIGN_IN) {
        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
        try {
            // Google Sign In was successful, authenticate with Firebase
            GoogleSignInAccount account = task.getResult(ApiException.class);
            Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId());
            firebaseAuthWithGoogle(account.getIdToken());
        } catch (ApiException e) {
            // Google Sign In failed, update UI appropriately
            Log.w(TAG, "Google sign in failed", e);
        }
    }
}
```

## リファクタリング後

自身が書いたコードを抜粋させて頂きます。
※ファイル名が上記と対応していないのはご了承ください。

あるイベント（ボタンが選択されたなど）をきっかけにsignInメソッドが呼ばれると、Googleサインイン画面を`ActivityResultLauncher.launch`で呼び出し、起動させます。Googleサインイン画面から戻ってきた時に、結果を`ActivityResultContracts.StartActivityForResult`で取得しています。

この`result`（引数）のデータ型は、`ActivityResult`というクラスです。`getResultCode()`や`getData()`をそれぞれ使うことで、requestCodeやIntentを取得できます。`ActivityResultLauncher.launch`側で、自らrequestCodeを設定しなくても良くなりましたね。

```LoginTopActivity.java
//Googleサインイン画面に遷移
private void signIn() {
    Intent signInIntent = mGoogleSignInClient.getSignInIntent();
    activityResultLauncher.launch(signInIntent);
}

//Googleサインイン画面から戻ってきた時に実行
private ActivityResultLauncher<Intent> activityResultLauncher =
            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {

                if (result.getResultCode() == Activity.RESULT_OK) {
                    if (result.getData() != null) {

                        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(result.getData());
                        try {

                            //Googleサインインに成功した場合、Firebaseで認証する
                            GoogleSignInAccount account = task.getResult(ApiException.class);
                            Log.d("LOGIN", "firebaseAuthWithGoogle:" + account.getId());
                            firebaseAuthWithGoogle(account.getIdToken());

                        } catch (ApiException e) {

                            //Googleサインインに失敗した場合、スナックバー表示
                            Log.w("LOGIN", "Google sign in failed", e);
                            Snackbar.make(view,getResources().getString(R.string.sb_failure_google_signin),Snackbar.LENGTH_SHORT).show();
                        }
                    }
                }
            });
```
# おわりに

今回は、Firebaseを用いたGoogleログイン実装において、二つのDeprecated箇所をリファクタリングしました。意外とシンプルな印象を受けた方も少なくないと思います。`ActivityResultLauncher`を用いたこの実装方法を参考にしてみてください。

現状、startActivityForResultとonActivityResultは非推奨ではあるものの、完全に使えない訳ではありません。しかし、打ち消し線があることで「どうにかしたい」という気持ちが働くのが人間の心理かなと思うので、是非そんな時はこの記事が少しでも役立てば嬉しいです。

# おまけ

今回のDeprecated箇所のリファクタリングは、自身がFirebaseを用いて簡単なAndroidアプリを作る過程で色々と調べた内容になります。そのAndroidアプリの概要は以下になります。もし少しでも興味がありましたら、ご覧ください。

> 【内容】
どんなアプリを作成したかを記録できるアプリ

> 【機能】
・Googleログイン（今回の内容はここ！！）
・メールログイン
・ユーザー登録
・ログアウト
・記録一覧
・記録追加
・記録更新
・記録削除

> 【Github】
[https://github.com/seiyaleb/DevelopRecordApp](https://github.com/seiyaleb/DevelopRecordApp)

> 今回のGoogleログインの実装は、[こちら](https://github.com/seiyaleb/DevelopRecordApp/blob/master/app/src/main/java/com/myapp/activity/LoginTopActivity.java)になります。

> 【動画】
![Android開発記録アプリ_動画.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2456250/23b72a08-0b69-9ac7-5667-5e8d52e0ab1f.gif)

# 参考サイト
* [https://firebase.google.cn/docs/auth/android/google-signin?hl=ja](https://firebase.google.cn/docs/auth/android/google-signin?hl=ja)
* [https://developer.android.com/training/basics/intents/result](https://developer.android.com/training/basics/intents/result)
* [https://developer.android.com/jetpack/androidx/releases/activity#1.2.0-alpha04](https://developer.android.com/jetpack/androidx/releases/activity#1.2.0-alpha04)
* [https://career.levtech.jp/guide/knowhow/article/386/](https://career.levtech.jp/guide/knowhow/article/386/)
* [https://buildersbox.corp-sansan.com/entry/2020/05/27/110000](https://buildersbox.corp-sansan.com/entry/2020/05/27/110000)
* [https://www.jisei-firm.com/android_develop4/](https://www.jisei-firm.com/android_develop4/)
* [https://qiita.com/atr/items/cc5d2a1eff9a0ba44990](https://qiita.com/atr/items/cc5d2a1eff9a0ba44990)