[Flutter+Firebase]はじめてのFlutter+Firebaseで詰まり散らかして力尽きた（失敗）[Flutter＋Firebaseの接続編]



#目的

- #flutter_meetup_tokyoの内容をアウトプットし、Flutter + Firebase と接続する。
 
元のプレゼン資料は[こちら](
https://speakerdeck.com/korodroid/flutterdefirebasefalseji-neng-wohuo-yong-siyou-number-gdgtokyo-number-flutter-meetup-tokyo)

#Firebaseで何かできるのか

Google公式のFlutter＋Firebaseのドキュメントによると、バックエンドにアクセス
>Firebase gives you access to backend services for mobile applications—including authentication, storage, database, and hosting—without maintaining your own servers. 


#Firebase特徴的な機能
##Firebase Authentication
複雑な認証処理をバックエンドと簡単に統合可能

例えば下記を実現できる。
- 既存のアカウント連携の実現
- ログインなしで利用可能
- 認証情報を一元管理（独自のサーバーをつかうとコスト高）

**注意 : 認証プロバイダごとに最適なプラグインが必要**
つまり、pubspec.yaml　に　```google_sign_in:^4.2.0``` などを追加する。


##Cloud Firestore
クラウドデータベース（NoSQL)
Flutterを使うことで端末側のデータを扱える

例えば下記を実現できる。
- クラウドバックアップ対応
- Android/iOS両対応
- オフライン対応

##Firebase Crashlytics
リアルタイムのクラッシュレポートツール

不具合発生時にすぐに対応できるようにする。

##Fluter＋Firebase　環境構築

①Flutterアプリの開発環境（IDE、エディタ）

②Firebaseログイン＆プロジェクト作成

③Firebaseのプロジェクト設定
　Android/iOSアプリの登録
　構成ファイルの取得、配置

④Firebaseの環境設定


⑤FlutterFireプラグインの追加→import文追加（*.dart)



##実際にFirebaseをFlutterに接続してみる。

公式ドキュメントをベースに進めます。詳細は省略しながら詰まった点を記述します。
公式ドキュメントは[こちら](https://codelabs.developers.google.com/codelabs/flutter-firebase/#0)
最終的にはこちらの[qiita投稿](https://qiita.com/unsoluble_sugar/items/95b16c01b456be19f9ac)に助けられました。

###①Flutterアプリの開発環境（IDE、エディタ）
###②Firebaseログイン＆プロジェクト作成
省略します。

###③　Firebase構成（Android/iOSとFirebaseを繋ぐということ？）

iOSでまずはやってみる。

####1 Firebaseの画面で、バンドル名を記入
<img width="1440" alt="Screen Shot 2020-07-15 at 10.28.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/26045e1b-7d8d-618c-2aaa-f58633f715d3.png">

**バンドルは固有のものが必要。取得方法は[こちら](https://codelabs.developers.google.com/codelabs/flutter-firebase/#6)がわかりやすかった**

####2　 ファイルをダウンロードして設置
Runnerの中に入れる。

<img width="1425" alt="Screen Shot 2020-07-15 at 10.27.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/81c65b28-7d66-b9cf-a54e-3f21a3a4b781.png">


####3 依存関係を管理するためにココアパッドをインストールする

<img width="1437" alt="Screen Shot 2020-07-15 at 10.31.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/103c6b38-d98a-5e3c-4f82-72a88cbaaf51.png">

しかし、pod Init として、ターミナルに```[!] No Xcode project found, please specify one```と怒られる。
cocoapods公式に下記のような記載を発見。
プロジェクト全体のではなく、iosのファイルの中に対して処理をするみたい。エラーはでなくなった。処理できたっぽい・・。

>Make sure to always open the Xcode workspace instead of the project file when building your project:

残りはがんがんスキップして完了してよい模様。

###③FlutterFireプラグインの追加→import文追加（*.dart)

[公式ドキュメント](https://flutter.dev/docs/development/packages-and-plugins/using-packages)　　と　こちらの[qiita投稿](
https://qiita.com/akeome/items/0a6ebf3af402fdf62c79)　が大変参考になりました。


FirebaseをFlutterで使えるようにするためには、依存関係の更新と、パッケージの導入が必要なようです。

####1　pubspec.yamlファイルの編集
dependenciesにcloud_firestoreを追加

```
dependencies:
  flutter:
    sdk: flutter
　firebase_core: ^0.2.5  # add dependency for Firebase Core

```

####2 プラグインのインストール

画面上部のPub get をクリック。少しわかりづらい場所にあります。
<img width="1440" alt="Screen Shot 2020-07-15 at 9.22.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/dba26e7d-06ba-af58-d383-0ee333d991c7.png">

#####詰まったポイント（インデント問題）

[こちらの記事が参考になりました](https://qiita.com/FShota/items/6fd2f9ab7fe8708f250e)
Flutterはインデントでデータ構造を示している（！）そのためインデントを変更し解決。
<img width="1440" alt="Screen Shot 2020-07-15 at 9.28.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/0ce243a5-aec7-0654-4352-89c69f891d93.png">


NG(当初インデントに問題あり）

```
dependencies:
  flutter:
    sdk: flutter
　　　firebase_core: ^0.2.5  # add dependency for Firebase Core

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.3
```

OK(cupertinoのインデントを上げる）
**適切なインデントは不明・・プラグインの抽象度がわかりません。**

```
dependencies:
  flutter:
    sdk: flutter
　firebase_core: ^0.2.5  # add dependency for Firebase Core

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
```


####３ パッケージのインポート

main.dartにパッケージをimportする。

#####しかしまたエラー。


<img width="833" alt="Screen Shot 2020-07-15 at 20.18.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665832/698c9140-30c1-66fa-7a1e-2a49f943d664.png">

[こちら](https://pub.dev/packages/firebase_auth#-installing-tab-)を見る限りimport文は間違えていない。
[open document先]https://dart.dev/tools/diagnostic-messages#unused_import

未使用とあるけれど、使いたいのだ・・。試しに ```  final GoogleSignIn _googleSignIn = GoogleSignIn();``` 使ってみたところ色がついたのでおそらく実際にコードを書くことでエラーは消えるはず。

###4 Info.plistにCFBundleURLTypes追加
 
```/ios/Runner/Info.plist``` に ```CFBundleURLTypes```を追加します。

```
<!-- Put me in the [my_project]/ios/Runner/Info.plist file -->
<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <!-- TODO Replace this value: -->
            <!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
            <string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
        </array>
    </dict>
</array>
<!-- End of the Google Sign-in Section -->
```

```CFBundleURLSchemes``` には、 ```GoogleService-Info.plist``` 内の```REVERSED_CLIENT_ID```キーの値をコピーして貼付。

このタイミングでビルドしてみた。が、インデントがぐちゃぐちゃ＋エラーで力尽きた😢😢
**to先輩方　おすすめのlinterあれば教えてください・・。**

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

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  final items = List<String>.generate(10000, (i) => "Item $i");
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
          primaryColor:Colors.white),
      home: Scaffold(
      appBar: AppBar(
//        centerTitle: false,
        leading:Icon(
          Icons.videocam
        ),
       title: const Text(
         'Hello Youtube!'
       ),
        actions:<Widget>[
          SizedBox(
            width:44,
           child: FlatButton(
            child:Icon(Icons.search),
             onPressed: (){

             },
            ),
          ),
          SizedBox(
           width:44,
           child:FlatButton(
               child:Icon(Icons.more_vert),
               onPressed: (){
            },
           ),
          ),
        ]
      ),
          body: Container(
            child: Column(
              children:<Widget>[
                Row(
                  children:<Widget>[
                    SizedBox(
                      width: 60,
                      child: Image.network(
                          'https://lh3.googleusercontent.com/OQicdb5sirirCCTLq2Z1J4tR_lU1DuYi7NMlaGvYBIYoi9jUuhI2Li4U_P3PDB1C4VcKtCLIoxyZX6EWPqeSfAgire5ktt0=s160-c'
                      ),
                    ),

                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          const Text(
                          'はじめてのFlutter',
                         ),
                          FlatButton(
                            child:Row(
                              children:<Widget>[
                                Icon(Icons.alarm),
                                Text('登録済み'),
                                Text('チャンネル登録者数　100万人')
                              ],
                            ),
                              onPressed:(){
                              }
                          )
                       ],
                    ),
                   ],
                ),
                Expanded(
                  child:ListView.builder(
                    itemCount:items.length,
                    itemBuilder:(context,index){
                      return ListTile(
                        contentPadding: EdgeInsets.all(8),
                          leading: Image.network(
                              'https://lh3.googleusercontent.com/OQicdb5sirirCCTLq2Z1J4tR_lU1DuYi7NMlaGvYBIYoi9jUuhI2Li4U_P3PDB1C4VcKtCLIoxyZX6EWPqeSfAgire5ktt0=s160-c'
                          ),
                        title:Column(
                          children:<Widget>[
                            Text('[はじめてのFlutter]まずはここから ${items[index]}'),
                            Row(
                              children:<Widget>[
                                Text('10k再生'),
                                Text('1日前'),

                              ]

                            )

                          ],
                        ),
                          trailing:Icon(Icons.more_vert),
                      );
                    }
                  )
                )
            ],
      ),
    ),
    ),
    );
  }class NextPage extends StatefulWidget {
  FirebaseUser userData;

  NextPage({Key key, this.userData}) : super(key: key);

  @override
  _NextPageState createState() => _NextPageState(userData);
  }

  class _NextPageState extends State<NextPage> {
  FirebaseUser userData;
  String name = "";
  String email;
  String photoUrl;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  _NextPageState(FirebaseUser userData) {
  this.userData = userData;
  this.name = userData.displayName;
  this.email = userData.email;
  this.photoUrl = userData.photoUrl;
  }

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

  @override
  Widget build(BuildContext context) {

  return Scaffold(
  appBar: AppBar(
  title: Text("ユーザー情報表示"),
  ),
  body: Center(
  child: Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
  Image.network(this.photoUrl),
  Text(this.name,
  style: TextStyle(
  fontSize: 24,
  ),
  ),
  Text(this.email,
  style: TextStyle(
  fontSize: 24,
  ),
  ),
  RaisedButton(
  child: Text('Sign Out Google'),
  onPressed: () {
  _handleSignOut().catchError((e) => print(e));
  },
  ),
  ]),
  ),
  );
  }
}

  class NextPage extends StatefulWidget {
  FirebaseUser userData;

  NextPage({Key key, this.userData}) : super(key: key);

  @override
  _NextPageState createState() => _NextPageState(userData);
  }

  class _NextPageState extends State<NextPage> {
  FirebaseUser userData;
  String name = "";
  String email;
  String photoUrl;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  _NextPageState(FirebaseUser userData) {
  this.userData = userData;
  this.name = userData.displayName;
  this.email = userData.email;
  this.photoUrl = userData.photoUrl;
  }

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

  @override
  Widget build(BuildContext context) {

  return Scaffold(
  appBar: AppBar(
  title: Text("ユーザー情報表示"),
  ),
  body: Center(
  child: Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
  Image.network(this.photoUrl),
  Text(this.name,
  style: TextStyle(
  fontSize: 24,
  ),
  ),
  Text(this.email,
  style: TextStyle(
  fontSize: 24,
  ),
  ),
  RaisedButton(
  child: Text('Sign Out Google'),
  onPressed: () {
  _handleSignOut().catchError((e) => print(e));
  },
  ),
  ]),
  ),
  );
  }



```