【Flutter】Windows, Webでのファイル選択・保存方法 [後編]
前編(Windowsアプリ)に引き続き、Webでのファイル選択・保存を実装します。
ファイル読込
ファイル読込(アップロード)はWindowsアプリと同一ソースで可能でした。
実装内容は前編を参照ください。
ファイル保存
ここからが本題で、読込が上手くいったので保存もそのままいけるかと思ったらそう甘くはありませんでした。
ファイル保存を実行してもうんともすんとも言いません。
確認してみるとgetSavePath
から空文字が返っていました。
(ファイル選択ダイアログでキャンセルを押下した場合はnull
が返る)
どういうことか調べると、以下のURL先にあるように、プラットフォームとしてファイルを開くことはサポートされていないようです。
更に明示的なキャンセルであるnull
と区別するために、プラットフォームとしてサポートしていない場合、空文字を返すようにしているようです。
つまり、WebアプリではgetSavePath
は使用できないので、getSavePath
で空文字が返って来た場合、他の手段で実装する必要があります。
代替手段
FlutterのWebアプリでファイル保存(ダウンロード)を実現するには、dart:html
パッケージのAnchorElement
を使用してダウンロードリンクを作成し発火させる方法があります。
getSavePath
で空文字が返ってきた場合のみ、AnchorElement
を使用したダウンロードに切り替えます。
import 'dart:html' as html;
---中略---
child: ElevatedButton(
onPressed: () async {
String? path = await getSavePath(acceptedTypeGroups: [
XTypeGroup(label: 'json', extensions: ['json'])
], suggestedName: "todoList.json");
print(path);
if (path == null) {
return;
}
if (path == "") { // 空文字の場合、AnchorElementでDLリンクを作成 → 発火
final anchor = html.AnchorElement(
href: "data:application/json;charset=utf-8," +
jsonEncode(todoList));
anchor.download = "todoList.json";
anchor.click();
} else {
final data =
Uint8List.fromList(json.encode(todoList).codeUnits);
final mimeType = "application/json";
final file = XFile.fromData(data, mimeType: mimeType);
await file.saveTo(path);
}
print(json.encode(todoList));
},
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
child:
Text("ファイル保存", style: TextStyle(color: Colors.white)),
),
これで無事、ファイルの保存が実現できました。
Windowsアプリでビルドエラー発生
これで一段落と思い、再度Windowsアプリのビルドを走らせてみるとエラーが発生しました。
原因はそのまま、dart:html
がデスクトップをサポートしていないためです。(当たり前)
しかし、上記のようにWebアプリで保存を実現するためにはdart:html
が必須です。
どうにか、条件設定などでdart:html
をimportしたままWindowsアプリをビルドできないかと調べてみましたが、どうも無理なようです。
ここで、ワンソースでのWindows,Webアプリ開発断念かと思いましたが、そういった環境のためのパッケージが存在しました。
Universal_htmlです。
このパッケージははクロスプラットフォーム開発用にdart:html
をデスクトップやモバイル環境でも使用できるようにしたもので、dart:html
をそのままpackage:universal_html/html.dart
に置き換えれば良いもののようです。
早速、インストールして、importを差し替えてみます。
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
file_selector: ^0.8.2
file_selector_windows: ^0.0.2
+ universal_html: ^2.0.8
- import 'dart:html' as html;
+ import "package:universal_html/html.dart" as html;
これで、無事Windows,Webともにビルドが通り、問題なく動作しました。
まとめ
手探りでWindowsアプリとWebアプリのファイル保存・読込を実装していきました。
一部分岐処理が必要になりましたが、ほぼワンソースで両アプリを開発できるFlutterのメリットを感じられました。
今回実装したソース(main.dartとpubspec.yaml)は以下に置いておきます。
Discussion