LoginSignup
23
23

More than 5 years have passed since last update.

flutterでfirebaseを使いチャットアプリを作る(firestore編)

Posted at

この記事は GameWith Advent Calendar 2018 の24日目です
GameWith Advent Calendar 2018 12日目の続きになります。
今回はfirestore編です。

必要なパッケージ

こちらをpubspec.yamlに追記します。

pubspec.yaml
cloud_firestore: ^0.8.2+3

firestoreとの連携と実装

cloud_firestoreのページを参考に実装していきます。

まずpackageを使用するためにimportします

import 'package:cloud_firestore/cloud_firestore.dart';

今回はチャットということでfiresotreのsnapshotを使用します。
参考ページにサンプルが載っているのでそれを今回は使用します。

送信

Future<void> addMessage(String text) {
  return Firestore.instance.collection("chat").add({
    "message": text
  });
}

Firestore.instance.collection で使用するコレクションを指定しaddでデータを追加します。

受け取り

StreamBuilder<QuerySnapshot>(
  stream: Firestore.instance.collection('chat').snapshots(),
  builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
    if (snapshot.hasError)
      return Text('Error: ${snapshot.error}');
    switch (snapshot.connectionState) {
      case ConnectionState.waiting: return new Text('Loading...');
      default:
        return ListView(
          padding: EdgeInsets.only(bottom: 80.0),
          children: snapshot.data.documents.map((DocumentSnapshot document) {
            return Text(document["message"]);
          }).toList(),
        );
    }
  }
)

snapshotを使用しているのでfirestoreのコレクションに値が追加されるとリアルタイムで反映されるようになりました。

snapshotについてはこちらを参考に
普通にデータを取りたい場合はget使用します。orderBywhereもあります。

完成品のコード

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter × firebase Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter × firebase Demor'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  FirebaseUser _user;

  void _setUser(FirebaseUser user) {
    setState(() {
      _user = user;
    });
  }

  final GoogleSignIn _googleSignIn = GoogleSignIn();
  final FirebaseAuth _auth = FirebaseAuth.instance;

  Future<FirebaseUser> _handleSignIn() async {
    GoogleSignInAccount googleUser = await _googleSignIn.signIn();
    GoogleSignInAuthentication googleAuth = await googleUser.authentication;
    FirebaseUser user = await _auth.signInWithGoogle(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    print("signed in " + user.displayName);
    return user;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _user == null ? googleAuthBtn() : chat()
    );
  }

  Widget googleAuthBtn() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          FlatButton(
            padding: EdgeInsets.all(20.0),
            color: Colors.blue,
            onPressed: () {
              _handleSignIn()
                .then((FirebaseUser user) => _setUser(user))
                .catchError((e) => print(e));
            },
            child: Text('google認証'),
          ),
        ],
      ),
    );
  }

  Widget chat() {
    final textController = new TextEditingController();

    Future<void> addMessage(String text) {
      return Firestore.instance.collection("chat").add({
        "message": text
      });
    }

    return Stack(
      children: <Widget>[
        StreamBuilder<QuerySnapshot>(
          stream: Firestore.instance.collection('chat').snapshots(),
          builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (snapshot.hasError)
              return Text('Error: ${snapshot.error}');
            switch (snapshot.connectionState) {
              case ConnectionState.waiting: return new Text('Loading...');
              default:
                return ListView(
                  padding: EdgeInsets.only(bottom: 80.0),
                  children: snapshot.data.documents.map((DocumentSnapshot document) {
                    return Text(document["message"]);
                  }).toList(),
                );
            }
          },
        ),
        Positioned(
          height: 80.0,
          left: 0.0,
          right: 0.0,
          bottom: .0,
          child: Container(
            decoration: BoxDecoration(
              color: Colors.white
            ),
            padding: EdgeInsets.only(top: 10.0, bottom: 20.0, left: 20.0, right: 20.0),
            child: Row(
              children: <Widget>[
                Expanded(
                  child: TextFormField(
                    controller: textController,
                  ),
                ),
                Expanded(
                  child: FlatButton(
                    padding: EdgeInsets.all(10.0),
                    color: Colors.blue,
                    onPressed: () {
                      addMessage(textController.text);
                      textController.text = '';
                    },
                    child: Text('送信'),
                  ),
                ),
              ],
            )
          ),
        ),
      ]
    );
  }
}

動作確認

シュミレーターを2つ起動して動かすとリアルタイムで反映されると思います。

スクリーンショット 2018-12-23 23.53.58.png

firestoreにもきちんと値が反映されています。

スクリーンショット 2018-12-23 23.54.28.png

flutterは公式のドキュメントも充実しており特に迷うことなく実装することができました。
widgetも豊富にあり、組み合わせていくだけでそれなりのものができそうです。
簡単なアプリなど個人制作などでflutterをお試しで今後も使っていこうと思います。

23
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23