メモ2ブログ

メモtoウェブログ。旧ブログはこちら。 http://sakebook.blogspot.jp/

パッケージが統合されたFlutter for Webへのアップグレード

Flutter for Webのパッケージがflutterに統合されました。それに伴い既存のFlutter for Webのプロジェクトでアップグレードが必要になったのでその記録です。

Upgrading

まだstableには来てないのでdevに向けて、webを有効にします。

$ flutter channel dev
$ flutter upgrade
$ flutter config --enable-web

channelの変更は、次のバージョンがstableに来たら不要になると思います

$ flutter --version
Flutter 1.10.6 • channel dev • https://github.com/flutter/flutter.git
Framework • revision cc3ca9a916 (5 days ago) • 2019-09-25 10:57:58 -0400
Engine • revision 63949eb0fd
Tools • Dart 2.6.0 (build 2.6.0-dev.0.0 69b5681546)

既存プロジェクトですでに作成済みの web/main.dart を削除します。

次に、プロジェクトをFlutter SDK向けに変更していきます。

AndroidiOSディレクトリを作成します

$ flutter create .

pubspec.yamlを置き換えて、flutter_webの部分をflutterに置き換えます。

web/assets/ に置いていた FontManifest.json の内容を移行します。

MaterialIconsは

flutter:
  uses-material-design: true

となり、

fontを利用していた場合は fonts フォルダをプロジェクトルートに作り、そこにフォントファイルを置きます。その後、font名の指定とfontのpathを書きます。

flutter:
  ...
  fonts:
    - family: KosugiMaru
      fonts:
        - asset: fonts/KosugiMaru-Regular.ttf

画像などの素材は、 assets フォルダをプロジェクトルートに作り、そこに移動させます。その後フォルダを指定します。

flutter:
  ...
  assets:
    - assets/

これで web/assets フォルダは空になったと思うので、削除します。

実行は次のコマンドです。Windowが立ち上がります。

$ flutter run -d chrome

ドキュメント的には以上なのですが、自分の環境では更に次のような手順が必要でした。

追加手順

rootBundleのimport

rootBundle を使っている場合、含まれるパッケージが変わっているので flutter/service からimportします。

import 'package:flutter/services.dart' show rootBundle;

assetsのパス

rootBundleでassetsにアクセスしている場合、pathが次のように変わります。

  • some.json

だったものが

  • assets/some.json

になります。assetsに指定しているフォルダからpathを指定する必要があります。

BinaryMessengerへのアクセス

runApp より早いタイミングで rootBundle を利用している場合、chromeのconsoleにエラーが出ます。

Uncaught (in promise) Error: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.
If you're running an application and need to access the binary messenger before `runApp()` has been called (for example, during plugin initialization), then you need to explicitly call the `WidgetsFlutterBinding.ensureInitialized()` first.
If you're running a test, you can call the `TestWidgetsFlutterBinding.ensureInitialized()` as the first line in your test's `main()` method to initialize the binding.

rootBundleがbinaryMessengerを利用しているため、怒られます。回避するためにはエラー文の通り、

WidgetsFlutterBinding.ensureInitialized()rootBundleより先に呼び出します。

dart:htmlのimportエラー

自分はIntelliJで開発しているのですが、Target of URI doesn’t exist: ‘dart:html’. のエラーが出ました。ですが、ターミナルからビルドする分には問題ありませんでした。

現状Dart SDKが提供しているもので、利用できるものとそうでないものがあるみたいです。

github.com

Release Buildのアウトプット先

今までは build/だったのですが、build/web/ に変わりました。Deployする際には注意が必要です。

リリースビルドのコマンドは次です。デフォルトでreleaseのconfigurationになっています。

$ flutter build web

まとめ

パッケージ統合以前のFlutter for Webのプロジェクトでも、アップグレードガイドがあるので移行自体はさっとできます。

ただし、いくつか注意点があるのでハマりすぎないように気をつけてください。

自分の環境において、マイグレーションのドキュメントに書いてないことで気をつける必要があったことは次の5点です。

  • rootBundleのimportが変わる
  • assetsのパスが変わる
  • assetsに早いタイミングでアクセスしている場合はWidgetsFlutterBinding.ensureInitialized() が必要になる
  • Dart SDKのいくつかのパッケージはWebでの利用に制限がある
  • アウトプットのpathが異なる

参考

Upgrading from package:flutter_web to the Flutter SDK · flutter/flutter Wiki · GitHub

Flutter: Unhandled Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized - Stack Overflow

Properly enable dart:html imports · Issue #35588 · flutter/flutter · GitHub

Building a web application with Flutter - Flutter