Flutter Web ファイル保存 エラー対応
Flutter Webで独自拡張子を持ったファイルをクライアントでダウンロードする機能を作成しようと試みる。
一般的にはAnchorElementでダウンロードみたいだが、クライアントでファイルの編集を行った後にダウンロードさせるため、うまくいかず...
いざダウンロードができた!とおもったらなぜかファイルが途中で切れてしまっている始末。
結論、コチラの記事を参照させていただき、解決したのでメモとして残しておく。
やりたいこと
以下の流れを Flutter Web上のボタン押下時に実行したい。
- サーバからjson形式でファイルをget
- getしたファイルをクライアント処理
- 処理したファイルを独自拡張子(私の場合は.scrn)でダウンロード
パッケージインストール
使用したパッケージ
file_selector
pubspec.yamlに追加
dependencies:
file_selector: ^0.8.4
pub get実行
> flutter pub get
ソースにimport
import 'package:file_selector/file_selector.dart';
ファイルをダウンロード
http パッケージでファイルをget
dart:convert で文字化けを処理
import "dart:convert";
import 'dart:html';
final _uri; // エンドポイント
final res = await get(Uri.parse(_uri));
final _decodeRes = utf8.decode(res.bodyBytes); // 文字化けするのでデコード
クライアントで処理
ここはあまり必要ないもしれないが、私の場合はgetしてきたファイルをクライアントで処理する必要があった。
(ユーザID等を現在のログインユーザの物に書き換える)
final String _data = _decodeRes.replaceAll(target, userId);
ダウンロード処理
ここからが本題。
今回の場合、ダウンロードしてもらうファイルの情報にカラーコードが含まれていたため、#FFFFFF
などがあるとこの #
をアンカーとして処理してしまい、ダウンロードされるファイルが途中で切れる。という問題が発生していた。(初歩的なところに気が付かなかった...)
また、クライアントでgetしたファイルを編集していたかつ、エンドポイントに「Authorization」ヘッダが必要だったので、anchorElementのhref要素に直接入れることができなかった。
対処法としては、デコードして編集した文字列をUnit8Listに変換し、file_selectorパッケージでblobオブジェクトに変換し、blobオブジェクトのパスをanchorElementに仕込んだらうまくいった。
import 'package:file_selector/file_selector.dart';
final _file = XFile.fromData(Uint8List.fromList(utf8.encode(_data))); // file_selectorの形式に変換
final _filePath = _file.path; // ここにblobオブジェクトのパスが入る
AnchorElement(href: _filePath)
..setAttribute('download', _fileName)
..click();
最後に
flutter webは2年前から触れているがやはり発展途上なのが否めない。
それでも型つき言語が使えること、好きなFlutterでWebアプリが作れるのは魅力だ。
Discussion