Flutter

Flutter web 配置したcsvファイルを開く方法

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 thehttppackage. 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 を初心者が学ぶおすすめの勉強法!【間違いない動画があります】Flutter 初心者が勉強する場合に、最高の動画をお伝えします。...

動画学習がしたい!という方にオススメの記事がこちらです。

【Udemy】スマホアプリ作成を学ぶときに受講しておきたい講座3選【Flutter】スマホアプリを初めて作成する場合、何らかの教材を見ながら進めると思います。 私は動画で学習するのが好きで、非常に効率よく学ぶことが...

Flutterの将来性はどうなのか?をまとめた記事はこちらです。

【2021/6 更新】Flutterの将来性をトレンドやGoogleの情勢から分析した結果クロスプラットフォーム開発のフレームワークの中で近年注目されているのが「Flutter」です。 私も2020年の4月頃から注目して...