🚗

Drift を Flutter Web で使う

2023/11/11に公開

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にライブラリを追加してインストールします。

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 のインストールは不要です。

次に

ダウンロードしてwebディレクトリに配置します。
web/ がこのようになればOK。

web/
├── favicon.png
├── index.html
├── manifest.json
├── drift_worker.js
└── sqlite3.wasm

データベースクラスの作成

libディレクトリの適当な場所にデータベースクラスを作成します。
今回はdriftディレクトリ配下に作成することにします。
Decksとは私が実際にアプリで利用しているテーブルの名前です。

lib/drift/decks_database.dart
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データベースと接続します。
WasmDatabasepackage:drift/wasm.dart から呼び出します。

lib/drift/decks_database.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操作用のお好みのメソッドを作成します。

lib/drift/decks_database.dart
...省略

(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を呼び出して使います。

lib/main.dart
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版の導入は公式記事だと全然情報が足りなかったので今回記事にしました。
特にココ

lib/drift/decks_database.dart
+ import 'package:drift/wasm.dart';

など、GitHub上で検索しないと出てこないのです。かなり困りました。
私のようにライブラリの導入だけで数日間悩んでしまわないように、この記事が誰かの役に立てば幸いです。

また、Drift は個人的に開発しているこちらのサービスで利用しています。

https://flash-pdf-card.web.app/

まだデモ版としてWeb版のみの公開なので、モバイル版へ正式移行する際に Drift 周りのあれこれが出てくることでしょう。
その件もまた記事にできればと思います。

GitHubで編集を提案

Discussion