Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

この記事は 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をお試しで今後も使っていこうと思います。

tanuki4
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした