Drift を Flutter Web で使う
Flutter WebでローカルDBを使いたい
Flutterでアプリ開発している中で、データの永続化にローカルDBを導入する必要が出てきました。
Flutter用のローカルDBライブラリはかなりの数ありますが、今回はWebでも利用可能な Drift を使ってみることにしました。
Flutter Web で Drift を利用しようとすると、ドキュメントだけでは実装が難解な部分があるのでこの記事で解説しようと思います。
Flutter Web の制限
Flutter はモバイルアプリ開発のためのフレームワークですが、Webでも利用することができます。
私はモバイルアプリとしてリリースする前にデモ版をWebで公開するようにしていて、Flutter Web はそのために利用しています。
ただしブラウザが任意のファイルパスの読み込みをサポートしていないためdart:io
やローカルストレージを素直に利用することができず、関連するライブラリの選定や利用方法には注意が必要です。
Drift とは
Drift は Web にも対応している Flutter 用のローカルDBライブラリです。
SQLite をラップして抽象化したもので、備えている ORM を使ったDB操作が可能です。
また Flutter Favorite program にも掲載されているため、品質も信用できそうです。
Drift を Flutter Web で使う
Drift を Flutter Web で使うには通常のセットアップ手順のうち一部の手順をこちらのページに書いてあるもので差し替えて進める必要があります。
ライブラリの導入
まずはpubspec.yaml
にライブラリを追加してインストールします。
dependencies:
drift: ^2.13.0
dev_dependencies:
drift_dev: ^2.13.0
build_runner: ^2.4.6
drift
: ライブラリ本体となるコアパッケージ
drift_dev
: リコードを生成に必要な開発用ツール
build_runner
: コード生成のための一般的なツール
sqlite3_flutter_libs
, path_provider
, path
のインストールは不要です。
次に
-
sqlite3.wasm
をsqlite3のリリースページから -
drift_worker.js
をdriftのリリースページから
ダウンロードしてweb
ディレクトリに配置します。
web/
がこのようになればOK。
web/
├── favicon.png
├── index.html
├── manifest.json
├── drift_worker.js
└── sqlite3.wasm
データベースクラスの作成
lib
ディレクトリの適当な場所にデータベースクラスを作成します。
今回はdrift
ディレクトリ配下に作成することにします。
Decks
とは私が実際にアプリで利用しているテーブルの名前です。
import 'package:drift/drift.dart';
part 'decks_database.g.dart';
class Decks extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text()();
}
(tables: [Decks])
class DecksDatabase extends _$DecksDatabase {}
build_runnerのコマンドでdatabase.g.dart
を自動生成します。
flutter pub run build_runner build --delete-conflicting-outputs
Webデータベースと接続する
NativeDatabase
の代わりに WasmDatabase
を使って作成したクラスをWebデータベースと接続します。
WasmDatabase
は package:drift/wasm.dart
から呼び出します。
import 'package:drift/drift.dart';
+ import 'package:drift/wasm.dart';
part 'decks_database.g.dart';
class Decks extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text()();
}
@DriftDatabase(tables: [Decks])
class DecksDatabase extends _$DecksDatabase {
+ DecksDatabase._(QueryExecutor e) : super(e);
+ factory DecksDatabase() => DecksDatabase._(connectOnWeb());
+ @override
+ int get schemaVersion => 1;
}
+ DatabaseConnection connectOnWeb() {
+ return DatabaseConnection.delayed(Future(() async {
+ final result = await WasmDatabase.open(
+ databaseName: 'decks_db',
+ sqlite3Uri: Uri.parse('sqlite3.wasm'),
+ driftWorkerUri: Uri.parse('drift_worker.js'),
+ );
+
+ if (result.missingFeatures.isNotEmpty) {
+ print('Using ${result.chosenImplementation} due to missing browser '
+ 'features: ${result.missingFeatures}');
+ }
+
+ return result.resolvedExecutor;
+ }));
+ }
基本的にはドキュメントの connectOnWeb
をそのまま使っています。
セットアップはこれで完了です。
メソッドを作成する
ここからはモバイルと同様です。
DB操作用のお好みのメソッドを作成します。
...省略
(tables: [Decks])
class DecksDatabase extends _$DecksDatabase {
DecksDatabase._(QueryExecutor e) : super(e);
factory DecksDatabase() => DecksDatabase._(connectOnWeb());
int get schemaVersion => 1;
// メソッドを設定
Future insertDeck(String title) {
return into(decks).insert(DecksCompanion.insert(title: title));
}
Future deleteDeck(int id) {
return (delete(decks)..where((deck) => deck.id.equals(id))).go();
}
Future updateDeck(int id, String title) {
return (update(decks)..where((deck) => deck.id.equals(id)))
.write(DecksCompanion(title: Value(title)));
}
}
...省略
DBを呼び出す
DBを呼び出して使います。
import 'package:flutter/material.dart';
import '../drift/decks_database.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final db = DecksDatabase();
await db.insertDeck('test');
List decks = await db.select(db.decks).get();
print(decks);
}
終わりに
Drift のWeb版の導入は公式記事だと全然情報が足りなかったので今回記事にしました。
特にココ
+ import 'package:drift/wasm.dart';
など、GitHub上で検索しないと出てこないのです。かなり困りました。
私のようにライブラリの導入だけで数日間悩んでしまわないように、この記事が誰かの役に立てば幸いです。
また、Drift は個人的に開発しているこちらのサービスで利用しています。
まだデモ版としてWeb版のみの公開なので、モバイル版へ正式移行する際に Drift 周りのあれこれが出てくることでしょう。
その件もまた記事にできればと思います。
Discussion