Flutter と Firestore
Flutter は Google が中心になって開発が進められているオープンソースのクロスプラットフォームに対応したモバイルアプリケーションフレームワークです。
1ソースでお手軽に iOS, Android のアプリをビルドすることができ、とっても素晴らしいフレームワークです。
Google謹製ということで、もちろん同じく Google が運営しているクラウドサービス Firebase とも連携できます。ここでは Flutter アプリに Firebase の中の1サービス Firestore を連携させる方法をまとめます。
サンプルアプリ
サンプルとして作るのは、Firestore 上の collection を一覧で表示する画面です。ボタンを押すとデータが追加され、その追加したデータが即座に反映されます。
では早速作っていきます。
まずは Flutter プロジェクトを作成します。
Flutter プロジェクトを作成する
$ flutter create flutter-firestore-sample
プロジェクト名を flutter_firestore_sample
として適当なディレクトリで作成します。とりあえず生成したままで、後で中身を作ります。
次に Firebaseのプロジェクトを作成して必要な設定を行います。
Firebase のプロジェクト設定
Flutter アプリに Firebase を追加する | Firebase
上のページを参考にしています。
Firebase コンソール を開き、新しくプロジェクトを作成します。
プロジェクト名を “flutter-firestore-sample” にし、ロケーションを東京にしています。これでプロジェクトを作成しましょう。
完了したらしたら次に進みます。
Android アプリ設定
Android のアイコンをクリックして Android アプリに Firebase を追加できるように設定していきます。
パッケージ名
まずはパッケージ名を入力します。パッケージ名には Android のアプリケーションIDを入力します。flutter プロジェクト内の android/app/build.gradle
ファイルに設定される applicationId
です。
今回は com.sample.flutter_firestore としました。この値を android/app/build.gradle
ファイルに設定します。
android {
// ..
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.sample.flutter_firestore" // ←をパッケージ名に合わせる
// ..
}
// ..
}
上記の通り android/app/build.gradle の内容を修正してください。修正点は applicationId のみです。
デバッグ用の署名証明書 SHA-1
Auth で Dynamic Links、Invites、Google ログイン、電話番号をサポートするために必須です。[設定] で SHA-1 を編集してください。
注: SHA-1 情報は Google ログインと Firebase Dynamic Links で必要です。
上記のような注意書きがありますが、書いてある通り Firestore のみを利用する場合にはこの SHA-1 情報は不要なのでとりあえず設定せずに進みます。設定したい場合は以下のページの手順で keytool を使って生成し、コピペしてください。
Authenticating Your Client | Google APIs for Android | Google Developers
では次に進みます。
google-services.json ファイルをダウンロード
ダウンロードボタンから google-services.json ファイルをダウンロードしてください。画像にある通りにプロジェクトにコピーしないといけません。
上記箇所にダウンロードしたファイルをコピペします。このファイル自体は後からでもダウンロード可能です。
Firebase SDK の追加
次は Firebase SDK の追加ですが、これを画面のサンプルのバージョンに合わせるとまずそうです。というのも以下のページには次のような注意書きがあります。
Flutter アプリに Firebase を追加する | Firebase
注: Flutter は現在、バージョン 3.2.1 の Google サービス プラグインと互換性があります。
ということで念のため Flutter のページにあるバージョンに合わせて追加します。追記するのは2ファイルあり、両方ともファイル名が build.gradle
なので混同しないように注意しましょう。
android直下とandroid/app直下にそれぞれ build.gradle という名前でファイルがあります。それぞれを以下のように行を追加してください。
android/build.gradle
buildscript {
// ...
dependencies {
// ...
// 以下の行を追加してください。
classpath 'com.google.gms:google-services:3.2.1' // Google Services plugin
}
}
allprojects {
// ...
repositories {
// 以下の行が存在しなければ追加してください。
google() // Google's Maven repository
// ...
}
}
android/app/build.gradle
dependencies {
// ...
}
// ...
// 最終行に以下の行を追加してください。
apply plugin: 'com.google.gms.google-services' // Gradle plugin
以上でAndroidアプリにかかわる設定は完了です。Firebase のアプリ設定は次に進んでインストールの確認は[このステップをスキップ]で終了してしまいましょう。
Firebaseのアプリ設定が中途半端になりますがこれでOKです。
Cloud Firestore データベースの作成
データベースを作成します。Firebase Console からプロジェクトを開き、Database のメニューを開きます。データベースを作成するボタンから新しい Firestore Database を作成します。
作成時に Cloud Firestore セキュリティールールの設定をどうするか聞かれるので、[テストモードで開始]を選択しておきます。実運用時にはセキュリティールールをしっかりと設定しましょう。
次にコレクションを作成します。今回は “books” というコレクションを作り、フィールドに “title”, “author” を持たせます。
上のように1件だけデータを作成しました。
Flutter アプリの開発
以下は通常の Flutter アプリの開発を進めていきます。先ほど作成したデータベースに接続し、データを読み込めるようにします。
まずは Firebase を利用するためのプラグインを導入します。
Firebase 関連のプラグインはこちらのページにまとまっています。
今回は Firestore を利用するので以下のプラグインを追加します。
cloud_firestore | Flutter Package
pubspec.yaml
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^0.9.13
pubspec.yaml を更新したら flutter packages get
でパッケージを追加します。
画面を作る
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() => runApp(MyHomePage());
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var count = 1;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Firestore Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Firestore Demo'),
),
body: createListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Firestore 上にデータを追加
Firestore.instance.collection('books').add({
'title': 'タイトル$count',
'author': '著者$count',
});
count += 1;
},
child: Icon(Icons.add),
),
),
);
}
createListView() {
Firestore.instance.collection('books').snapshots().listen((data) {
print(data);
});
return StreamBuilder(
stream: Firestore.instance.collection('books').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
// エラーの場合
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
// 通信中の場合
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading ...');
default:
return ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['title']),
subtitle: new Text(document['author']),
);
}).toList(),
);
}
},
);
}
}
Firestore へのアクセスの方法はプラグインのページにいくつか例があります。
上のコードも基本それに倣っています。
簡単に説明すると QuerySnapshot
というのが監視できる Firestore のオブジェクトで、上の例だと “books” という collection の変更を監視しています。変更を検知すると、自動で Widget を再構築してくれるのが StreamBuilder です。
StreamBuilder を使うと自分で状態を管理せずとも変更に応じて書き換えが行われるので便利です。エラーや読み込み中の状態も保持しているのでそれぞれに応じた描画が可能です。
以下動かしてみたときのイメージです。後ろでコンソールを直接いじってデータを追加しています。
いい感じに Widget が書き換えられているのがわかります。追加ボタンに応じでデータも追加されます。もちろんクラウド上に追加されたデータは保持されているので、アプリを再起動しても状態が復元されます。
以上、サンプル実装と解説でした。以下、私が実装している途中に遭遇したビルドエラーの対処法をメモして終わります。
ビルドエラー
D8: Cannot fit requested classes in a single dex file (# methods: 71610 > 65536)
このエラーはメソッド数が 65536 を超えるとビルドできないという制約に引っかかったときに発生するものです。自分が作成したメソッドだけでなく利用するライブラリのメソッドも含みます。
今回だと Firebase のライブラリを導入するに当たりこのエラーが発生する可能性があります。
このエラーを突破するには android/app/build.gradle
に設定を追加する必要があります。
android/app/build.gradle
android {
defaultConfig {
...
minSdkVersion 21
targetSdkVersion 26
// ↓これを追加
multiDexEnabled true
}
// ..
}
dependencies {
// minSdkVersion が 20 以下の場合のみ
// ↓これを追加
compile 'com.android.support:multidex:1.0.3'
}
コメントを書く