Open12

Flutter Webの可能性を探ってみる(主にマップ周り)

ピン留めされたアイテム
Yuta-KTDYuta-KTD

やりたいこと
今度作る(かもしれない)アプリで、Flutter webを使うかもしれないので、どのくらい現実的に使えるものなのか調べてみる

  • そもそも動くのか
    • できないことは?
  • パフォーマンスは良好なのか?
Yuta-KTDYuta-KTD

https://flutter.dev/multi-platform/web
Flutter on the Webが正式名称とのこと

https://docs.flutter.dev/platform-integration/web/renderers
レンダリングの仕組みとしては、FlutterのDartやC++のコードをJavaScriptもしくはWebAssembly(Wasm)に変換して、それをブラウザ側に渡して動かすというもの(ざっくり理解)。
モバイルとはちょっと仕組み違う。モバイルは独自のレンダリングエンジンを使って動かしているはず(うろ覚え)
canvaskit側に以下のように書いてあるけど、これはDart→ロジック部分、UI→Widgetとして書いた部分(Flutterに近いところ)みたいな理解でいいのかな?

Dart code is compiled to JavaScript, and the UI is rendered on the main thread into WebGL.

Google EarthはFlutter on the Web で動いている模様。

Flutter3.22からWasmサポートがstableになった。それまではJavaScriptサポートのみ。

Yuta-KTDYuta-KTD

Wasmってなんだ?
https://zenn.dev/tetter/scraps/da36684a96709d
https://qiita.com/sachaos/items/e3a613b018febb898fde

W3Cが2019年に標準化した、Webブラウザ上で動作する第4の言語。

対応している任意のプログラミング言語を中間言語へと変換し、Wasmファイル(.wasm)として保存する。実行時にブラウザによってWebアプリケーションの一部としてダウンロードされ、ブラウザによって検証された後にプロセッサに応じた機械語へと変換されて動作する。

以下の特徴を持つ
Language-independent (言語非依存)
Portable/Platform-independent (ポータブル/プラットフォーム非依存)
Safe (安全)
Fast (高速)

Yuta-KTDYuta-KTD

FlutterでWasmビルドされたアプリを使用するには、ブラウザがWasmGC(WebAssembly Garbage Collection)なるものをサポートしている必要がある。
https://docs.flutter.dev/platform-integration/web/wasm

To run a Flutter app that has been compiled to Wasm, you need a browser that supports WasmGC.

https://developer.chrome.com/blog/wasmgc?hl=ja

https://zenn.dev/cybozu_frontend/articles/20231214_wasmgc
https://zenn.dev/askua/articles/afe3a3b43b82cb

Yuta-KTDYuta-KTD

flutter build webでWebアプリをビルドしてみた。

$ tree build/web 
build/web
├── assets
│   └── 省略
├── canvaskit
│   ├── canvaskit.js
│   ├── canvaskit.js.symbols
│   ├── canvaskit.wasm
│   ├── chromium
│   │   ├── canvaskit.js
│   │   ├── canvaskit.js.symbols
│   │   └── canvaskit.wasm
│   ├── skwasm.js
│   ├── skwasm.js.symbols
│   ├── skwasm.wasm
│   └── skwasm.worker.js
├── favicon.png
├── flutter.js
├── flutter_bootstrap.js
├── flutter_service_worker.js
├── icons
│   └── 省略
├── index.html
├── main.dart.js
├── manifest.json
└── version.json

flutter build web --wasmでビルドした結果、main.dart.mjsmain.dart.wasmというファイルが追加でビルドされていた。

Yuta-KTDYuta-KTD

ビルドしたものをローカルで動かしてみる
dhttpd '--headers=Cross-Origin-Embedder-Policy=credentialless;Cross-Origin-Opener-Policy=same-origin'
このオプションの通りで、サーバーからこのヘッダーが帰らないと多分Wasmで動かないんだと思う。
オプションあり
オプションあり
オプションなし
オプションなし

Yuta-KTDYuta-KTD

私はマップ表示を頻繁に使用するため、マップ表示を試してみる(
https://pub.dev/packages/google_maps_flutter_web を見れば一通りセットアップは簡単にできた。

パッケージはgoogle_maps_fluttergoogle_maps_cluster_managerを使用した。
色々触ってて気づいたけど、そもそも現在位置が表示されてない。
既知の問題で、myLocationButtonEnabledmyLocationEnabledのオプションは無視されるとのこと。
https://github.com/flutter/flutter/issues/64073

Yuta-KTDYuta-KTD

もっと基礎的なところで、そもそもWeb対応しているパッケージ名はpub.devでPlatforms:Webで調べれば出てくる
(個人的に)よく使うパッケージ名について調べてみた

パッケージ名 Web対応しているか メモ
http ⭕️ Clientを使い分ける必要あり?
shared_preferences ⭕️ LocalStorageで実現
geolocator ⭕️ getLastKnownPositionやアプリ設定画面を開くメソッドは非対応
flutter_secure_storage ⭕️ WebCryptoを使用して実現。セキュリティ対策必須。
riverpod ⭕️
flutter_inappwebview ⭕️
google_maps_cluster_manager ⭕️? 特に使えるとは書いてなかったが、結果使えた
Yuta-KTDYuta-KTD

デプロイしようと思い難読化周りが気になった。

Web apps don't support obfuscation. A web app can be minified, which provides a similar result. When you build a release version of a Flutter web app, the web compiler minifies the app. To learn more, see Build and release a web app.

ビルドする時に軽量化を行なっており、それによって難読化と同様の結果が得られるらしい

https://docs.flutter.dev/deployment/obfuscate

Yuta-KTDYuta-KTD

デプロイしてみる。
柿を参考に単一のFirebaseプロジェクトで、3つのビルド方法でデプロイしてみた

  • flutter build web --wasm
  • flutter build web --web-renderer canvaskit
  • flutter build web --web-renderer html

https://zenn.dev/tsuruo/articles/6a1d29caa43974
https://zenn.dev/pressedkonbu/articles/deploy-flutter-web-app-with-firebase-hosting

https://pagespeed.web.dev/?hl=ja で速度を計測してみたが、大きな違いはなさそうだった

wasmビルド

canvaskitビルド

htmlビルド

Yuta-KTDYuta-KTD

Flutter Webの2024年のロードマップをみると

We'll continue to focus on performance and quality, including investigating reducing the overall application size, better use of multi-threading, supporting platform views, improving app load times, making CanvasKit the default renderer, improving text input, and investigating options for supporting SEO for Flutter web.
We expect to complete the effort to compile Dart to WasmGC, and with that support Wasm compilation of Flutter web apps. This also includes a new JS interop mechanism for Dart that supports both JS and Wasm compilation.
We also plan to resume work to support hot reload on the web.

  • SEO→未対応
  • WASMビルド→対応完了、あとはブラウザ対応待ち
  • ホットリロード→未対応
Yuta-KTDYuta-KTD
  • やりたいことが十分にできるかというと、マップで現在地表示ができない時点でかなり厳しいと感じた
  • 本当に作りたいものを実現するには、OSSコントリビュートしまくるしかなさそう
    • 少なくとも要件に対して、「モバイルと同じアレを使えばできそう」みたいな感覚は絶対NG
  • ただ、内部的なロジックは手を加えずとも動きそうな気配を感じた
    • 課題は描画周り
    • ゼロから開発するときに、管理画面とかに使うのであれば十分商用に耐えうるのでは(使ってる会社さんもありました Altiveさんとか)
  • 速度の話は正直よくわからなかった、比較対象をReactとかで作ったものとかにするべきだったかもしれない。