[Flutter]Firebase AuthenticationでGoogleログインを利用して認証する

最近Flutterでアプリ開発の学習を始めたtaiktです。

ユーザーログインをするようなアプリを作ろうと思い、Firebase AuthenticationとGoogleログインを使ってユーザー認証をしてみましたので備忘録もかねて手順を残します。

# Flutterプロジェクトの作成
Flutterプロジェクトは公式を参考に作成。
https://flutter.dev/docs/get-started/install

# Firebaseプロジェクトの設定
Firebase Authenticationの機能を利用するためまずはFirebaseの設定をします。

### プロジェクト作成
まずはFirebaseのコンソールからプロジェクトを作成します。
- プロジェクト名を入力
- Google Analyticsの設定を勧められますが今回はテストなので未設定にします
- プロジェクトの作成

### アプリの設定
アプリでFirebaseを使うためにアプリの設定をします。
今回はAndroidのアプリを設定しました。

プロジェクトのホーム画面でAndroidを選択。
![android.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/009cdb84-6373-435c-2011-0c4a7f0c5c83.png)

アプリの情報を入力します。
![android_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/9cc0a1bc-a557-74fe-3eb7-e2327776dc88.png)

#### Androidパッケージ名
アプリレベルのbundle.gradleファイルのapplicationIdに記載があります。(android/app/bundle.gradle)

#### デバッグ用の署名証明書 SHA-1
Googleログインの利用に必要になるのでこちらも設定します。

keytoolを利用してSHA-1ハッシュを取得できます。

```
keytool -list -v \
-alias androiddebugkey -keystore ~/.android/debug.keystore
```

### google-service.jsonをFlutterアプリに追加
Firebaseの構成ファイル(google-service.json)をダウンロードしてFlutterプロジェクトの`android/app/`配下に置きます。
![gsjson.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/83c1edda-f907-4c1d-234f-439ed10da914.png)

### Gradleファイルを修正する
google-servicesプラグインを利用できるようにします。

プロジェクトレベルのgraldeファイルにgoogle-servicesのプラグインを追加。

```android/bundle.gradle
dependencies {
        classpath 'com.google.gms:google-services:4.2.0'
    }
```

アプリレベルのgradleファイルに下記を追加。

```android/app/bundle.gradle
dependencies {
//...
}
pply plugin: 'com.google.gms.google-services'
```

## ログイン処理の実装
まずはFirebaseとGoogleログインのプラグインをFlutterに追加します。

```pubspec.yml
firebase_core: 0.4.4+3
firebase_auth: 0.16.0
google_sign_in: ^4.0.14
```

次にログイン処理を行う画面を実装します。

```Login.dart
import 'package:flutter/material.dart';
// https://pub.dev/documentation/google_sign_in/latest/google_sign_in/google_sign_in-library.html
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';

class Login extends StatefulWidget {
  @override
  _Login createState() => _Login();
}

class _Login extends State<Login> {
  final GoogleSignIn _googleSignIn = GoogleSignIn();
  final FirebaseAuth _auth = FirebaseAuth.instance;

  Future<FirebaseUser> _handleSignIn() async {
    GoogleSignInAccount currentUser = _googleSignIn.currentUser;

    try {
      currentUser ??= await _googleSignIn.signInSilently();
      currentUser ??= await _googleSignIn.signIn();
      if (currentUser == null) return null;

      final GoogleSignInAuthentication googleAuth = await currentUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.getCredential(
          idToken: googleAuth.idToken,
          accessToken: googleAuth.accessToken
      );
      final FirebaseUser user = (await _auth.signInWithCredential(credential)).user;
      return user;
    } catch(e) {
      print(e);
    }
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('Chat')
      ),
      body: Center(
          child: Column(
            children: <Widget>[
              SizedBox(height: 24.0),
              FlatButton(
                  child: Text('SignIn'),
                  onPressed: () => _handleSignIn()
                      .then((FirebaseUser user) {
                        print(user);
                        Navigator.pushReplacementNamed(context, "/");
                  }).catchError((e) => print(e))
              )
            ],
          )
      ),
    );
  }
}
```

これでGoogleログインで認証したユーザーの情報が取得できるようになりました。

認証したユーザーの情報を表示してみます。

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

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  FirebaseUser user;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  Future<void> _handleSignOut(context) async {
    await FirebaseAuth.instance.signOut();
    try {
      await _googleSignIn.signOut();
    } catch (e) {
      print(e);
    }

    Navigator.pushReplacementNamed(context, "/");
  }

  @override
  void initState() {
    super.initState();
    FirebaseAuth.instance
        .currentUser()
        .then((currentUser) => {user = currentUser});
  }

  @override
  Widget build(BuildContext context) {
    print(this.user.displayName);
    return Scaffold(
        body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Text(user.displayName),
                FlatButton(
                    child: Text('SignOut'), onPressed: () => _handleSignOut(context))
              ],
            )
        )
    );
  }
}
```

Googleアカウントのユーザー名が表示されました。
![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/2e50b30e-2c0c-a2e1-f8c9-114e44c945d4.png)

# 参考
Firebaseプロジェクト設定
https://firebase.google.com/docs/flutter/setup?hl=ja

ログイン処理まわり
https://pub.dev/packages/firebase_auth