📁

Flutter Web ファイル保存 エラー対応

2022/03/11に公開

Flutter Webで独自拡張子を持ったファイルをクライアントでダウンロードする機能を作成しようと試みる。
一般的にはAnchorElementでダウンロードみたいだが、クライアントでファイルの編集を行った後にダウンロードさせるため、うまくいかず...
いざダウンロードができた!とおもったらなぜかファイルが途中で切れてしまっている始末。

結論、コチラの記事を参照させていただき、解決したのでメモとして残しておく。

やりたいこと

以下の流れを Flutter Web上のボタン押下時に実行したい。

  • サーバからjson形式でファイルをget
  • getしたファイルをクライアント処理
  • 処理したファイルを独自拡張子(私の場合は.scrn)でダウンロード

パッケージインストール

使用したパッケージ
file_selector

pubspec.yamlに追加

pubspec.yaml
dependencies:
  file_selector: ^0.8.4

pub get実行

> flutter pub get

ソースにimport

***.dart
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