FlutterでGoogle認証を使ったFirebase Authentication

## はじめに
Flutterを使ってネイティブアプリを作っているが、Widgetの使い方やFirestoreとのデータ連携の仕方など、コードの書き方が分からずそれなりに苦労している。
一旦分かってしまえばかなり高速でアプリ開発ができそうなので、使い方やコードの書き方のメモを残しておく。
先日`Firesbase Authentication` を使ったログイン機能を実装してみたが、今回はGoogle認証の機能も試してみたので、その時のメモを残す。

## Flutterの実行環境

- Ubuntu 18.04LTS（GCP上）
- Flutter 1.22.6
- Dart 2.10.5
- Android Studio 4.1.2
- VScode 1.53.0
　　

## メモ内容
今回も少しステップが多いので、簡単に章分け。　※開発環境がMacではないので今回はandroidのみの話。
１．Firebase側の設定
２．Flutter側の準備　　
３．Google認証を使ったサンプルコード

※プロジェクトの作成や、FlutterからFirebaseを呼びだす基本設定は既に完了しているものとする。以下の記事を参考に。
　[**【FlutterでFirebase Authenticationを使ったログインUIを作成してみた。】**](https://qiita.com/smiler5617/items/b004debc847ffed4e3af)
　[**【FlutterからCloud Firestoreのデータ取得 ＆ データ書き込み】**](https://qiita.com/smiler5617/items/8dcf720f5477a5f4b7d7)の１章

## １．Firebase側の設定

#### Google認証の有効化

下図の様に、FirebaseのコンソールからGoogle認証を有効にする。
![Qiita-No037_img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/7cc413c1-07b8-1034-5321-bffa96e8ad19.jpeg)

『プロジェクトの公開名』 と 『プロジェクトのサポートメール』を入力して保存する。
![Qiita-No037_img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/ffd4014b-9242-636b-d245-706bc0e79cbe.jpeg)

#### SHA1 フィンガープリントの登録

アプリの SHA1 フィンガープリントをコピー。
　※開発環境はGCP上のUbuntuなので、以下のコマンドで取得。【SHA1:】のアスタリスクの部分をコピー

```shell:TERMINAL
$ keytool -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore

Alias name: androiddebugkey
Creation date: Mar 10, 2021
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: C=US, O=Android, CN=Android Debug
Issuer: C=US, O=Android, CN=Android Debug
Serial number: 1
Valid from: Wed Mar 10 14:53:43 UTC 2021 until: Fri Mar 03 14:53:43 UTC 2051
Certificate fingerprints:
	 SHA1: ***********************************************************************
	 SHA256: ********************************************************************
Signature algorithm name: SHA1withRSA (weak)
Subject Public Key Algorithm: 2048-bit RSA key
Version: 1
```
`Keystore Password` を求められて覚えがない場合は、"**changeit**" or 何も入力せず`Enter` を試してみる。

※もし以下の様なエラーが出た場合は、`openjdk` をインストールする。

```shell:TERMINAL
Command 'keytool' not found, but can be installed with:
# ↑↑↑↑↑
# もしこのメッセージが出たら、以下のコマンドを実行。
$ sudo apt install openjdk-11-jre-headles 
```

コピーしたフィンガープリントを、Firebaseコンソールに登録。
`プロジェクトの概要隣の歯車マーク ＞ プロジェクトを設定　＞ 画面下の【フィンガープリントを追加】`
![Qiita-No037_img04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/acdb705c-4c9c-1def-678e-107328701ac5.jpeg)
![Qiita-No037_img05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/9dce8e60-ba5f-f1ba-e379-59ccaa3fffb3.jpeg)

**これでFirebase側の設定は完了！**


## ２．Flutter側の準備
`プロジェクトディレクトリ > pubspec.yaml` は以下の様に編集する。

```yaml:pubspec.yaml
# --- 省略 ---

dependencies:
  flutter:

  # firebase
  firebase_core: ^0.4.0+9
  firebase_auth: ^0.14.0+5
  cloud_firestore: ^0.13.5
  google_sign_in: ^4.0.14  # ← ここがGoogle認証を利用するために追加した行

# --- 省略 ---
```

必要なパッケージをインストール

```bash:TERMINALより実行（本記事ではVScode上で実行）
$ flutter pub get
```


一旦ここで`main.dart`にimport文を追加して保存したら、`flutter run` を実行し、問題なくパッケージが読み込めているか確認。

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

// ここが追記部分！
import 'package:google_sign_in/google_sign_in.dart';

//--- 省略 ---
```

**これでFlutter側の準備も整った！**


## ３．Google認証を使ったサンプルコード
今回サンプルコードとして作成してみたログイン機能の画面レイアウトと画面遷移は以下の様な感じ。
![Qiita-No037_img06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/0872ce6c-51f8-5c0f-3930-ca15eff1ef3f.jpeg)



起動後の初期画面のコンテンツや処理内容は、全て`main.dart`に記載。
　※今回はGoogle認証の部分がメインなので、Firebase側の機能は作り込んでいない。いつものことだが悪しからず......

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'home.dart';

void main() {
 runApp(App());
}

class App extends StatelessWidget {

 @override
 Widget build(BuildContext context) {

    return MaterialApp(
      debugShowCheckedModeBanner: true,  // <- Debug の 表示を OFF

      home: TestPage(),
    );
  }
}


class TestPage extends StatelessWidget {

  // Google 認証
  final _google_signin  = GoogleSignIn(scopes: [
     'email',
     'https://www.googleapis.com/auth/contacts.readonly',
    ]);
  GoogleSignInAccount googleUser;
  GoogleSignInAuthentication googleAuth;
  AuthCredential credential;

  // Firebase 認証
  final _auth = FirebaseAuth.instance;
  AuthResult result;
  FirebaseUser user;
  
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[

                ButtonTheme(
                  minWidth: 350.0,
                  // height: 100.0,
                  child: RaisedButton(
                    child: Text('Google認証',
                      style: TextStyle(fontWeight: FontWeight.bold),),
                    textColor: Colors.white,
                    color: Colors.grey,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),

                    onPressed: () async {
                      
                      // Google認証の部分
                      googleUser = await _google_signin.signIn();
                      googleAuth = await googleUser.authentication;
                      
                      credential = GoogleAuthProvider.getCredential(
                        accessToken: googleAuth.accessToken,
                        idToken: googleAuth.idToken,
                      );
                      
                      // Google認証を通過した後、Firebase側にログイン　※emailが存在しなければ登録
                      try {
                        result = await _auth.signInWithCredential(credential);
                        user = result.user;
                        
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => Home(user_id: user.uid),
                          )
                        );
                      
                      } catch (e) {
                        print(e);
                      }
                    }
                  ),
                ),

                ButtonTheme(
                  minWidth: 350.0,
                  // height: 100.0,
                  child: RaisedButton(
                    child: Text('Google認証ログアウト',
                      style: TextStyle(fontWeight: FontWeight.bold),),
                    textColor: Colors.white,
                    color: Colors.grey,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),

                    onPressed: () {
                      _auth.signOut();
                      _google_signin.signOut();
                      print('サインアウトしました。');
                    }
                  ),
                ),

                Text('別のGoogleアカウントでログインしたい場合、一回ログアウトする必要がある。'),

              ],
            ),
        ),
    );
 }
}
```

認証通過後の遷移先画面のコンテンツは`home.dart`に記載。

```dart:home.dart
import 'package:flutter/material.dart';

// [Themelist] インスタンスにおける処理。
class Home extends StatelessWidget {

  final String user_id;
  Home({Key key, this.user_id}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body:Center(
        child:Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('ようこそ',
              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
            Text(user_id),
          ],
        ),
      ),
    );
  }
}
```

FirebaseのコンソールからAutheticationのユーザー登録情報を確認してみると、初回ログイン後は以下の様になっているはず。
![Qiita-No037_img07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/4c972437-087c-840d-eab0-0bf476f94aac.jpeg)
　※当たり前だが、コンソールなどからユーザーを削除すると、再度同じGoogleアカウントでログインした場合でも再登録となるため、**【ユーザーUID】** は新しいものが自動で振られる。

**ざっとだが、一応ここまででFlutterからGoogle認証でFirebase Authentication を利用するとこまで完了！**


## おまけ
先日のログインUIにGoogle認証も追加したので、gitにアップロードしました。
　https://github.com/Smiler5617/flutter_functions/tree/master/login_func_FirebaesAuthentication2/lib
　※先日のログインUIの記事  ⇒ 　[**【FlutterでFirebase Authenticationを使ったログインUIを作成してみた。】**](https://qiita.com/smiler5617/items/b004debc847ffed4e3af)

画面レイアウトはこんな感じ。
![Qiita-No037_img08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/eb01f48a-80a5-ac5b-0246-0087b59c0885.jpeg)