【Mac不要】iOSとAndroidのFlutterアプリから利用者のGoogle Photosにアクセスする手順 - Codemagic編 (前編)

# はじめに

※この記事は、以下の記事の続編です。

[【Mac不要】FlutterアプリにFirebase Crashlyticsを組み込んでiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/67e26b661167863f0b9b)

この記事ではその後、Flutterアプリから利用者のGoogle Photoにアクセスするための手順を説明しますが、この(前編)では、利用者のGoogleアカウントにアクセスできるまでの手順を説明します。

では早速始めてみましょう。

## 前提

この記事は、以下に当てはまる人向けの iOS/Android 対応アプリにGoogle Sign-in APIを組み込む手順を紹介します。

* 開発機はWindowsだ
* **Macを持っていない**
* Flutterで開発したい
* Apple Developer Programに既に登録している。

## 開発環境の前提

以下の3本の記事の手順に沿ってFlutterアプリをCodemagicでビルドし、さらに自身のiOS端末/Android端末のアプリの利用状況(Analytics)やクラッシュ情報(Crashlytics)がFirebaseに連携されている状態にしておいてください。

1. [【Mac不要】開発中のFlutter製アプリをiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/c7ed113d0ecdf7e48ff0)
1. [【Mac不要】FlutterアプリにFirebase SDKを組み込んでiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/d3b72f5c0aa97e6c1c08)
1. [【Mac不要】FlutterアプリにFirebase Crashlyticsを組み込んでiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/67e26b661167863f0b9b)

## ソースコードの公開

この記事の手順で作成したソースコードはGithubで公開しています。併せてご参照ください。
~~https://github.com/atsuteru/flutter_firebase_0507/tree/Qiita-GooglePhoto-v1.0~~
**5/14 修正** Firebase認証を利用するように修正しました。
https://github.com/atsuteru/flutter_firebase_0507/tree/Qiita-GooglePhoto-v1.1

# 本文

## 自身のアプリに対しFirebase上でGoogle Photos Library APIを有効化する

Firebaseコンソールにサインインし、[Photos Library APIのページ](https://console.developers.google.com/apis/library/photoslibrary.googleapis.com)を開きます。

ページ最上部の「Google APIs」のタイトルのすぐ右で、自身のFirebase Appを選択しましょう。そして「有効にする」ボタンをクリックしてください。
![API とサービス - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 18_40_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/d059ba43-82ef-c410-c957-516cf4e17979.png)

すると、以下の画面に切り替わります。これで有効化できました。
![API とサービス - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 18_41_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/748d44b7-32b1-bdaa-ad7b-0d58d8417368.png)

次に、OAuth同意画面の構成を行います。OAuth同意画面とは、アプリの利用者に対して表示する、「このアプリはこれらの権限を要求します」ことを通知する同意画面のことです。

ではページ左側のメニューから「認証情報」をクリックし、[認証情報のページ](https://console.developers.google.com/apis/api/photoslibrary.googleapis.com/credentials)を開いてください。
![API とサービス - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 18_47_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/53fe2416-24fe-7712-7bc7-130ff1d65332.png)

このページの右上付近「同意画面を構成」をクリックします。するとOAuth 同意画面の設定ウィザードが開きます。

最初のページでは、この記事の場合はすべての利用者をターゲットとすので、「外部」を選択し、「作成」をクリックします。
![API とサービス - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 18_49_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/f6de910f-de4c-43ee-af76-98234a594934.png)

次のページでは、最低限、`アプリケーション名`、`サポートメール`と、`Google API のスコープ`を設定します（他の項目はリリースに向けて追々設定しましょう）。`アプリケーション名`を入力したら、「スコープの追加」ボタンを押してください。
![API とサービス - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 18_55_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/b72d56b2-fc27-96e9-edd8-ad3b3fd41a81.png)

するとスコープの追加画面が表示されます。ここで必要なスコープを選択するのですが、Google Photos APIのスコープはリストに用意されていないので、画面下部の「手動で貼り付け」のリンクをクリックします。
![API とサービス - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 18_55_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/c631a9e7-a685-e2b0-9ad2-e3691df3cd97.png)

すると入力欄が出現しますので、以下を貼り付けてください。

```text:スコープの追加
https://www.googleapis.com/auth/photoslibrary
https://www.googleapis.com/auth/photoslibrary.sharing
```

貼り付けたら、画面下部の「追加」をクリックしましょう。すると「スコープの追加」ボタンの上に2行、`photoslibrary`が追加されているのが分かるはずです。
![同意画面 - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 19_01_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/98c9402b-c4f3-e306-6d44-81e88c7539c1.png)

※ここで「プライベート データにかかわるスコープを追加したため、スコープの公開前に、同意画面で Google による確認が必要です」という警告が表示されます。これは開発段階のアプリではまだ不要なので、このままスキップして構いません。もしGoogleによる確認を受けたい場合は、[このFAQページのVerification for apps](https://support.google.com/cloud/answer/7454865)を参考にご準備ください。

最後に保存を押せば、設定は完了です。
![同意画面 - flutter-firebase-0507 - Google API コンソール - Google Chrome 2020_05_12 19_03_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/8d464f9f-ce36-e17b-02fa-c1a18904f821.png)

では続けて、アプリの準備に取り掛かりましょう。

Flutterアプリ側では、`google_sign_in`プラグインを利用します。[google_sign_inプラグインのページ](https://pub.dev/packages/google_sign_in)を確認し、以下の手順を進めていきましょう。

## Android向けの設定

以下、[Android integration](https://pub.dev/packages/google_sign_in#android-integration)のページより。

Android向けの追加の設定は不要です。

## iOS向けの設定

以下、[iOS integration](https://pub.dev/packages/google_sign_in#ios-integration)のページより。

iOS向けに、以下のファイルに`Google Sign-in Section`の設定を追加します。

```text:ios/Runner/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...(中略)...
    <!-- Google Sign-in Section -->
    <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>COPY_REVERSED_CLIENT_ID_HERE</string>
        </array>
      </dict>
    </array>
    <!-- End of the Google Sign-in Section -->
</dict>
```

上記を貼り付け後、`COPY_REVERSED_CLIENT_ID_HERE`の部分を、以下のファイルの`key=REVERSED_CLIENT_ID`の値(string)に貼り換えましょう。**※以下、マスクしてありますので、あなたのファイルの値を貼り付けてください**

```text:ios/Runner/GoogleService-Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CLIENT_ID</key>
	<string>***.apps.googleusercontent.com</string>
	<key>REVERSED_CLIENT_ID</key>
	<string>com.googleusercontent.apps.***-***</string>
...(中略)...
</dict>
```

iOS向けの追加の設定は以上です。

## Flutterアプリの実装

以下、[Example](https://pub.dev/packages/google_sign_in#example)のページより。

コーディングは、説明しやすいように若干アレンジしています。

### Google Sign-inライブラリを読み込む設定を追加する

`pubspec.yaml`の`dependencies`に、`google_sign_in`の行を追加しましょう。

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^0.4.4+3
  firebase_crashlytics: ^0.1.3+3
  google_sign_in: ^4.0.7
```

### アプリの実装にGoogle Sign-in処理を組み込む

本記事では説明しやすいように、あえて`main.dart`のみで実装しました。実際はお好みのデザインパターンで実装されてください。

**5/14 追記**

**Flutter1.7 (AndroidX対応)以降では、以下のコードでは不足があることが分かりました。
最新のコードはもう少し先にある「5/14 追加手順 Flutter1.7 (AndroidX対応)」の章をご利用ください。**

#### import宣言の追加と、サインイン用のインスタンス生成

```dart:lib/main.dart
import 'dart:async';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';
// ▼▼▼ importの追加ココカラ ▼▼▼
import 'package:google_sign_in/google_sign_in.dart';
// ▲▲▲ importの追加ココマデ ▲▲▲

// ▼▼▼ サインイン用のインスタンス生成の追加ココカラ ▼▼▼
final GoogleSignIn _googleSignIn = GoogleSignIn(scopes: <String>[
  'profile',
  'https://www.googleapis.com/auth/photoslibrary',
  'https://www.googleapis.com/auth/photoslibrary.sharing'
]);
// ▲▲▲ サインイン用のインスタンス生成の追加ココマデ ▲▲▲

void main() {
  Crashlytics.instance.enableInDevMode = true;
  FlutterError.onError = Crashlytics.instance.recordFlutterError;
  runZoned<Future<void>>(() async {
    runApp(MyApp());
  }, onError: Crashlytics.instance.recordError);
```
#### Stateクラスへの変数とメソッドの追加

```dart:lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
// ▼▼▼ 変数の追加ココカラ ▼▼▼
  GoogleSignInAccount _currentUser;
// ▲▲▲ 変数の追加ココマデ ▲▲▲

// ▼▼▼ メソッドの追加ココカラ ▼▼▼
  @override
  void initState() {
    super.initState();
    _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) {
      setState(() {
        _currentUser = account;
      });
      if (_currentUser != null) {
        _handleGetContact();
      }
    });
    _googleSignIn.signInSilently();
  }

  Future<void> _handleGetContact() async {
  }

  Future<void> _handleSignIn() async {
    try {
      await _googleSignIn.signIn();
    } catch (e, s) {
      Crashlytics.instance
          .recordError(e, s, context: 'Google SignIn error');
    }
  }

  Future<void> _handleSignOut() => _googleSignIn.disconnect();
// ▲▲▲ メソッドの追加ココマデ ▲▲▲

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
```
#### サインインを実行するためのWidgetの追加

```dart:lib/main.dart
// ▼▼▼ Widget の追加ココカラ ▼▼▼
  Widget _buildGoogleSignInBody() {
    if (_currentUser != null) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          ListTile(
            leading: GoogleUserCircleAvatar(
              identity: _currentUser,
            ),
            title: Text(_currentUser.displayName ?? ''),
            subtitle: Text(_currentUser.email ?? ''),
          ),
          const Text("Signed in successfully."),
          RaisedButton(
            child: const Text('SIGN OUT'),
            onPressed: _handleSignOut,
          ),
          RaisedButton(
            child: const Text('REFRESH'),
            onPressed: _handleGetContact,
          ),
        ],
      );
    } else {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          const Text("You are not currently signed in."),
          RaisedButton(
            child: const Text('SIGN IN'),
            onPressed: _handleSignIn,
          ),
        ],
      );
    }
  }
// ▲▲▲ Widget の追加ココマデ ▲▲▲

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            Text(
              'Firebase Crashlytics Tests:',
            ),
            FlatButton(
                child: const Text('Key'),
                onPressed: () {
                  Crashlytics.instance.setString('foo', 'bar');
                }),
            FlatButton(
                child: const Text('Log'),
                onPressed: () {
                  Crashlytics.instance.log('baz');
                }),
            FlatButton(
                child: const Text('Crash'),
                onPressed: () {
                  Crashlytics.instance.crash();
                }),
            FlatButton(
                child: const Text('Throw Error'),
                onPressed: () {
                  throw StateError('Uncaught error thrown by app.');
                }),
            FlatButton(
                child: const Text('Async out of bounds'),
                onPressed: () {
                  Future<void>.delayed(const Duration(seconds: 2), () {
                    final List<int> list = <int>[];
                    print(list[100]);
                  });
                }),
            FlatButton(
                child: const Text('Record Error'),
                onPressed: () {
                  try {
                    throw 'error_example';
                  } catch (e, s) {
                    // "context" will append the word "thrown" in the
                    // Crashlytics console.
                    Crashlytics.instance
                        .recordError(e, s, context: 'as an example');
                  }
                }),
// ▼▼▼ Widget の呼び出しの追加ココカラ ▼▼▼
            _buildGoogleSignInBody(),
// ▲▲▲ Widget の呼び出しの追加ココマデ ▲▲▲
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
```

## 動作確認

実装が完了したら、pushしてCodemagicのビルド結果を待ちましょう。

Codemagicから届いたビルド成功の通知メールから、再インストールしましょう。

※iOSアプリは、TestFlightの手順（記事：[【Mac不要】開発中のFlutter製アプリを仲間のiOS端末に実機配備する手順 - Codemagic&TestFlight編](https://qiita.com/kami_teru/items/6d5c9b24f711f1270697)）をすでに実施している場合は、TestFlightから「Update」することでこのバージョンをインストールしましょう。それ以外はの方はCodemagicから届くメールからインストールしてください。

### Androidでの動作確認
* SIGN INボタンが追加されていますね！早速押してみましょう。<br/>
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/01e69d28-ae12-72ef-fc28-40efb1a45e39.jpeg">
* Googleアカウントへのサインイン画面が表示されました！デバイスのアカウントでそのままサインインしてみます。<br/>
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/76ebee05-58b6-ac90-afd5-040b58ae63a5.jpeg">
* 次はGoogleアカウントに対してアプリに与えられる権限の確認が続きます。<br/>
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/6d21faed-85cd-d0bf-2f74-5cdb412a050e.jpeg">
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/2a1a4749-756b-c695-8621-fadcc39ec764.jpeg">
* まだ権限の確認が続きます。最後に「許可」をクリックしましょう。<br/>
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/b4c97431-e2e6-eaea-8ac0-9fce76a026e8.jpeg">
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/685853b9-b6cd-2ec7-6518-15eaa182e6ba.jpeg">
* すると・・・サインインできましたね！<br/>
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/190fbfe4-4550-81b1-103c-c91a4b3f3662.jpeg">

注記）上記はUSBデバッグにて確認を行いました。現在、CodemagicのビルドからインストールしたAndroidアプリでは、「SIGN INボタンクリック」→「アカウントの選択」の後、ホーム画面に戻ってしまう不具合が発生しており、~~解決方法は見つけられていません。。。どなたか、解決のヒントをお持ちであればご教授いただけると有難いです。~~
**5/14追記 解決方法が見つかりました。この後に追加の手順を記載してありますので、お読みください。**

### iOSで確認

* SIGN INボタンが追加されていますね！早速押してみましょう。<br/>
<img width="320" alt="IMG_1527.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/f1b971a9-d34b-dec4-dbe4-e7965fdf20ed.jpeg">
* するとiOSからの確認ダイアログが表示されます。続けましょう。<br/>
<img width="320" alt="IMG_1528.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/496715ce-922a-3f9a-5e39-cb76004886a5.jpeg">
* Googleアカウントへのサインイン画面が表示されました！入力していきましょう。<br/>
<img width="320" alt="IMG_1529.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/65d5a257-2978-0408-c140-f44345684d52.jpeg">
<img width="320" alt="IMG_1530.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/d6264cd5-aef9-dab2-cc12-a0f2ccbbbd45.jpeg">
* すると物騒な警告画面が表示されました。これは、**開発中のためGoogleによる確認をスキップしているから**です。`詳細`から`安全ではないページ委に移動`を行いましょう。<br/>
<img width="320" alt="IMG_1531.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/7dc5d6fc-cae1-f31d-2734-24c154e487b7.jpeg">
<img width="320" alt="IMG_1532.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/561b88f5-6f78-8503-4746-66a92732f020.jpeg">
* 次はGoogleアカウントに対してアプリに与えられる権限の確認が続きます。<br/>
<img width="320" alt="IMG_1533.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/763b18d4-7567-f63d-a2bf-2a237c9ead0e.jpeg">
<img width="320" alt="IMG_1534.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/0618d24b-c5a5-f896-4292-86f2431a734a.jpeg">
* まだ権限の確認が続きます。最後に「許可」をクリックしましょう。<br/>
<img width="320" alt="IMG_1535.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/d789f757-991a-496b-a9d3-8df0180d4829.jpeg">
<img width="320" alt="IMG_1536.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/209e360b-9df8-05a2-093c-519424bb78d4.jpeg">
* すると・・・サインインできましたね！<br/>
<img width="320" alt="IMG_1538.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/b71c5ba8-02d6-fff2-0c45-da4ef867aeae.jpeg">

## 5/14 追加手順 Flutter1.7 (AndroidX対応)

ここまでの実装では、Android端末での実機の動作に問題がありました。原因は、Flutter1.7以降に必要な手順の漏れです。以下の記事から、Flutter1.7以降では、GoogleアカウントにサインインするためにはFirebase認証を経由しなければならなくなったことを知りました。

[Flutter: Implementing Google Sign In](https://medium.com/flutter-community/flutter-implementing-google-sign-in-71888bca24ed)

では早速その手順をすすめましょう。以下の手順は、次のサイトを参考にしています。

[Firebase authentication & Google sign in using Flutter - Codemagic blog](https://blog.codemagic.io/firebase-authentication-google-sign-in-using-flutter/)



### Firebaseコンソール上でGoogleアカウントのAuthenticationを有効にする

* Firebaseコンソールから、アプリのAuthenticationのページを開き、「ログイン方法の設定」ボタンをクリックしましょう。
![flutter-firebase-0507 - Authentication - Firebase コンソール - Google Chrome 2020_05_13 21_51_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/86bfedb3-f35d-cf97-0608-00ed80647040.png)
* 対応しているログインプロバイダの一覧が表示され、その中の`Google`を選択します。
![flutter-firebase-0507 - Authentication - Firebase コンソール - Google Chrome 2020_05_13 21_51_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/5f025b82-c2be-64e1-6f12-8ffd1ba8bd7c.png)
* 「有効にする」に切り替えたら、「保存」をクリックしましょう。手順は以上です。
![flutter-firebase-0507 - Authentication - Firebase コンソール - Google Chrome 2020_05_13 21_52_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/00d44c3b-6d07-1d2a-3dec-335a8e4c1db3.png)

### FlutterアプリにFirebase Authenticationのライブラリを組み込む

`pubspec.yaml`にプラグイン`firebase_auth`を追加します。最新のバージョンは[firebase_authプラグインのページ](https://pub.dev/packages/firebase_auth)で確認しましょう。
※ついでに`google_sign_in`のバージョンも最新にしました。

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^0.4.4+3
  firebase_crashlytics: ^0.1.3+3
  firebase_auth: ^0.16.0
  google_sign_in: ^4.4.6
```

### Flutterアプリの実装を、Firebase Authenticationを使う形に書き換える

以下、`main.dart`を編集していきます。

#### import宣言の追加と、サインイン用のインスタンス生成

```dart:lib/main.dart
import 'dart:async';
// ▼▼▼ importの追加ココカラ ▼▼▼
import 'package:firebase_auth/firebase_auth.dart';
// ▲▲▲ importの追加ココマデ ▲▲▲
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';
// ▼▼▼ importの追加ココカラ ▼▼▼
import 'package:google_sign_in/google_sign_in.dart';
// ▲▲▲ importの追加ココマデ ▲▲▲

// ▼▼▼ サインイン用のインスタンス生成の追加ココカラ ▼▼▼
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn(scopes: <String>[
  'profile',
  'https://www.googleapis.com/auth/photoslibrary',
  'https://www.googleapis.com/auth/photoslibrary.sharing'
]);
// ▲▲▲ サインイン用のインスタンス生成の追加ココマデ ▲▲▲

void main() {
  Crashlytics.instance.enableInDevMode = true;
  FlutterError.onError = Crashlytics.instance.recordFlutterError;
  runZoned<Future<void>>(() async {
    runApp(MyApp());
  }, onError: Crashlytics.instance.recordError);
```
#### Stateクラスへの変数とメソッドの追加

```dart:lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
// ▼▼▼ 変数の追加ココカラ ▼▼▼
  FirebaseUser _currentUser;
// ▲▲▲ 変数の追加ココマデ ▲▲▲

// ▼▼▼ メソッドの追加ココカラ ▼▼▼
  @override
  void initState() {
    super.initState();
    new Future(() async{
      if (await _handleSignIn(await _googleSignIn.signInSilently())) {
        _handleGetContact();
      }
    });
  }

  Future<void> _handleGetContact() async {
  }

  Future<bool> _handleSignIn(GoogleSignInAccount googleSignInAccount) async {
    if (googleSignInAccount == null) {
      return false;
    }
    final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
    final AuthCredential credential = GoogleAuthProvider.getCredential(
      accessToken: googleSignInAuthentication.accessToken,
      idToken: googleSignInAuthentication.idToken,
    );
    final AuthResult authResult = await _auth.signInWithCredential(credential);
    final FirebaseUser user = authResult.user;
    if (user.isAnonymous) {
      return false;
    }
    if (await user.getIdToken() == null) {
      return false;
    }
    final FirebaseUser currentUser = await _auth.currentUser();
    if (user.uid != currentUser.uid) {
      return false;
    }
    setState(() {
      _currentUser = currentUser;
    });
    return true;
  }

  Future<void> _handleSignOut() async {
    await _googleSignIn.signOut();
    setState(() {
      _currentUser = null;
    });
  }
// ▲▲▲ メソッドの追加ココマデ ▲▲▲

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
```
#### サインインを実行するためのWidgetの追加

```dart:lib/main.dart
// ▼▼▼ Widget の追加ココカラ ▼▼▼
  Widget _buildGoogleSignInBody() {
    if (_currentUser != null) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          Card(
            color: Colors.lightBlueAccent,
            child: ListTile(
              leading: CircleAvatar(
                backgroundImage: NetworkImage(
                  _currentUser.photoUrl,
                ),
                radius: 30,
                backgroundColor: Colors.transparent,
              ),
              title: Text(_currentUser.displayName ?? ''),
              subtitle: Text(_currentUser.email ?? ''),
            ),
          ),
          const Text("Signed in successfully."),
          RaisedButton(
            child: const Text('SIGN OUT'),
            onPressed: _handleSignOut,
          ),
        ],
      );
    } else {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          const Text("You are not currently signed in."),
          RaisedButton(
            child: const Text('SIGN IN'),
            onPressed: () async{
              if (await _handleSignIn(await _googleSignIn.signIn())) {
                _handleGetContact();
              }
            }
          ),
        ],
      );
    }
  }
// ▲▲▲ Widget の追加ココマデ ▲▲▲

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            Text(
              'Firebase Crashlytics Tests:',
            ),
            FlatButton(
                child: const Text('Key'),
                onPressed: () {
                  Crashlytics.instance.setString('foo', 'bar');
                }),
            FlatButton(
                child: const Text('Log'),
                onPressed: () {
                  Crashlytics.instance.log('baz');
                }),
            FlatButton(
                child: const Text('Crash'),
                onPressed: () {
                  Crashlytics.instance.crash();
                }),
            FlatButton(
                child: const Text('Throw Error'),
                onPressed: () {
                  throw StateError('Uncaught error thrown by app.');
                }),
            FlatButton(
                child: const Text('Async out of bounds'),
                onPressed: () {
                  Future<void>.delayed(const Duration(seconds: 2), () {
                    final List<int> list = <int>[];
                    print(list[100]);
                  });
                }),
            FlatButton(
                child: const Text('Record Error'),
                onPressed: () {
                  try {
                    throw 'error_example';
                  } catch (e, s) {
                    // "context" will append the word "thrown" in the
                    // Crashlytics console.
                    Crashlytics.instance
                        .recordError(e, s, context: 'as an example');
                  }
                }),
// ▼▼▼ Widget の呼び出しの追加ココカラ ▼▼▼
            _buildGoogleSignInBody(),
// ▲▲▲ Widget の呼び出しの追加ココマデ ▲▲▲
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
```

これで対応は完了です。

# おわりに

以上で(前編)は終わりです。

(後編)では、いよいよ、Google Photo APIをコールして、アルバムの情報などを取得していきたいと思います。乞うご期待！

最後に、この記事がFlutterを始められる方にとって少しでも助けになれば、幸いです。