Flutter webでサイトを作成することにハマっているkazuproです。
最近Flutter webを使いこなせるようになりたくて、ガツガツと開発しているのですが、HTMLとJavascriptを使って作成しているときには困らないことでも、Flutter webでは「あれ?これどうすれば良いんだ?」ということがそこそこ起きています。
Flutterでアプリを作成するときは、配置してあるファイルを簡単に開くのは「dart:io」を使用することで簡単にできますが、Flutter webでは「dart:io」を使用することができないため、簡単にはできませんでした。
File Pickerというパッケージで、ユーザーが選んだファイルを読み込むことは簡単にできるようですが、自分のフォルダに配置してあるファイルをどうしても開きたい!
悪戦苦闘しましたが、なんとか実現することができました。
今回はFlutter webで、配置してあるファイルを読み込む方法を備忘として残しておきます。
Flutter webでは「dart:io」を使用することができない
配置してあるファイルを開く時、普通のFlutterであれば「dart:io」を使用することで簡単にファイルを読み込むことができます。
import 'dart:io'; final file = File("test.csv");
これだけでファイルを読み込むことができます。
しかし、Flutter webでは「dart:io」を使用することができません。
実際にブラウザで開くと以下のようなエラーが出て使用することができません。
Flutterの公式でもブラウザでは使えないよと記載されていますね。
Can I use dart:io with a web app?
No. The file system is not accessible from the browser. For network functionality, use the
http
package. Note that security works somewhat differently because the browser (and not the app) controls the headers on an HTTP request.https://flutter.dev/docs/development/platform-integration/web#can-i-use-dartio-with-a-web-app
dart:ioを使用することができないので、別の方法を考える必要が出てきました。
解決策1:Javascriptを呼ぶことにした
dart:ioは使用できないし、良いパッケージも見つからなかったので路頭に迷っていましたが、そういえばDartってJavaScriptを呼ぶことができるじゃんということを思い出しました。
なのでJavaScriptの「XMLHttpRequest」を使えばファイルを読み込む事ができるというわけですね。
JavaScriptは以下の通り
function getCSV(url){ return new Promise((resolve, reject) => { let req = new XMLHttpRequest(); req.open('GET', url, true); req.onload = function() { if (req.status === 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function() { reject(new Error(req.statusText)); }; req.send(); }); }
Flutter側は以下の通り
import 'dart:js_util'; import 'package:js/js.dart'; @JS() library assetstest; @JS('getCSV') external getCSV(String url); Future<void> getCSVForWeb() async { var promise = getCSV('yahoo.csv'); var qs = await promiseToFuture(promise); print(qs); }
これでファイルを読み込むことができました。
ポイントは「dart:js_util」のpromiseToFuture()を使用することで、Javascriptがpromiseを返してきたときにFutureに変換して、Dartでも扱えるようにしているところです。
解決策2:rootBundleを使用する
わざわざJavaScriptなんて呼ばなくても、「rootBundle」を使用すれば、assetsで読み込んだファイルを読むことができました。
ソースは非常にシンプルに書くことができます。
import 'package:flutter/services.dart'; final String csv = await rootBundle.loadString('assets/yahoo.csv');
これだけでOKです。
JavaScriptで読み込むよりもシンプルに読むことができました。
まとめ
Flutter webではアプリを作るときには簡単にできたことでも、webではできなくなっていることがあります。
そんなときに、日本語の情報が薄いの少ないのでどん詰まりしてしまうことがありますね。。。
英語の情報を気合で読む必要がありそうです。
Flutter学習情報
Flutterを勉強するのに最適な参考書は、以下の「基礎から学ぶFlutter」です。
環境構築から、Dart/Flutterの基本/テストやパフォーマンスチューニングまで一通り学ぶことができます。
また、当ブログではFlutterを初心者が学ぶためにオススメな方法を「Flutter を初心者が学ぶおすすめの勉強法!【間違いない動画があります】」という記事で公開していますので、Flutterに興味がある方は是非読んでみてください。
動画学習がしたい!という方にオススメの記事がこちらです。
Flutterの将来性はどうなのか?をまとめた記事はこちらです。