Slide 1

Slide 1 text

div要素の中に、Flutterを埋め込んでみよう
 〜(ベータ版)Element Embeddingを試す〜 beeeyan (主要パッケージがバージョン 1.0.0になっていない、という意味ではまだベータかも)

Slide 2

Slide 2 text

本日のゴール
 ● FlutterのElement Embeddingで何ができるかを知る。
 ● Element Embeddingの公式サンプルコードを通して、実 装方法を知る。
 
 +α
 Element Embeddingの活用方法の考察


Slide 3

Slide 3 text

Element Embeddingとは?
 Element Embedding : 要素埋め込み
 
 Flutterの文脈においては Widgetを標準的なウェブの
に追加できる。 この方法で統合されると、Flutterは単にウェブコンポーネントに変わり、 DOMとシームレスに統合される。 ただ、
の中に表示されるだけではなく、JavaScriptなどで状態を操作できる。 https://www.youtube.com/watch?v=PAOAjOR6K_Q&t=199s

Slide 4

Slide 4 text

公式のdemoサイト https://flutter-forward-demos.web.app/#/
 


Slide 5

Slide 5 text

導入方法 導入方法 前提条件
 
 ● Dartのバージョン 3.0.0
 Flutterの3.10.0バージョンで利用できる


Slide 6

Slide 6 text

window.addEventListener('load', function(ev) { ・・・省略・・・ }); ↓  
・・・省略・・・ window.addEventListener("load", function (ev) { // Embed flutter into div#flutter_target let target = document.querySelector("#flutter_target"); _flutter.loader.loadEntrypoint({ onEntrypointLoaded: async function (engineInitializer) { let appRunner = await engineInitializer.initializeEngine({ hostElement: target, }); await appRunner.runApp(); }, }); }); プロジェクト作成後、 web/index.htmlを書き換え flutter_targetのセレクタを追加 デフォルトのloadEntrypointの記述を 変更してhostElementを追加

Slide 7

Slide 7 text

import 'package:flutter/material.dart'; import 'package:js/js.dart' as js; import 'package:js/js_util.dart' as js_util; ~~ @js.JSExport() class _MyAppState extends State { // 調査 final _streamController = StreamController.broadcast(); int _counterScreenCount = 0; @override void initState() { super.initState(); final export = js_util.createDartExport(this); js_util.setProperty(js_util.globalThis, '_appState', export); js_util.callMethod(js_util.globalThis, '_stateSet', []); } ~~ main.dart (1/2) js/js.dart js/js_util.dart をimportする。 ※これらのパッケージが Dart 3でないと動かない。 JavaScriptでも利用したい。Exportしたい 部分に 「@js.JSExport()」を付与 「_MyAppState」を「_appState」という JavaScriptのプロパティとして扱えるように、 「setPropertty」する。

Slide 8

Slide 8 text

main.dart (2/2) final _streamController = StreamController.broadcast(); @js.JSExport() void increment() { setState(() { _counterScreenCount++; _streamController.add(null); }); } @js.JSExport() void addHandler(void Function() handler) { _streamController .stream.listen((event) { handler(); }); } StreamController.broadcast 複数のリスナーが同時にデータを受け取ることができるスト リーム 変更をHTML・JavaScript側に反映させるた め。 ※反映処理のcallbackを受け取る部分は、 main.dartのaddHandlerに処理がある。

Slide 9

Slide 9 text

web/js/demo-js-interop.js let appState = window._appState; ~~ let valueField = document.querySelector("#value"); let updateState = function () { valueField.value = appState.count; }; // Register a callback to update the HTML field from Flutter. // Streamの処理を検知しているのはここ appState.addHandler(updateState); let incrementButton = document.querySelector("#increment"); incrementButton .addEventListener ("click", (event) => { appState.increment(); }); ~~ DartのState・処理にアクセスできるよう 「appState」を呼び出す。 ボタンの押下のイベントを検知して 「appState.increment()」でmain.dart のincrementを呼び出す。 main.dartのaddHandlerには updateStateを引数に入れる。

Slide 10

Slide 10 text

HTML上のボタンを押下 ↓ jsからdartのincrementを呼び出す ↓ dartでincrement後、streamの処理を 実行 ↓ dartのaddHandlerを実行 ↓ addHandlerの引数の「handler」の中に jsのupdateStateの処理が入っていて、 HTML上の表示が更新される。 jsからmain.dartのincrementを呼び出す
 ↓
 main.dartで値をincrementした後、streamの処理を実行
 ↓
 main.dartのaddHandlerを実行
 ↓
 addHandlerの引数の「handler」の中にjsのupdateStateの処理が入ってい て、HTML上の表示が更新される。
 
 HTML上のボタンを押下した際、
 何が起きているか?
 
 


Slide 11

Slide 11 text

web/css/style.css #flutter_target { border: 1px solid #aaa; width: 320px; height: 480px; border-radius: 0px; transition: all 150ms ease-in; } 忘れないように! CSSでFlutter画面を表示する領域は 確保しておくこと。 ※Flutter部分は自動で領域を持たな い。 (自力で実装しようとすると引っかかるかも)

Slide 12

Slide 12 text

ライブコーディング(時間があれば) 「decrement」ボタンの追加 web/index.htmlにボタン追加 main.dartに処理追加 @js.JSExport() void decrement() { setState(() { _counterScreenCount --; _streamController.add(null); }); }

Slide 13

Slide 13 text

web/js/demo-js-interop.jsに処理追加 let decrementButton = document.querySelector("#decrement"); decrementButton.addEventListener("click", (event) => { appState.decrement(); });

Slide 14

Slide 14 text

Element Embeddingの利点は?
 Flutter Webの弱点部分を組み合わせを解消するアプローチ
 ● SEO
 ● (初期読み込みなど)スピード
 その他
 ● Flutterで既に作成したWidgetをWebでも利用したい。
 ● モバイルアプリの画面をWebで表示してみたい。
 (スクレイピングさせたくない要素をFlutterで表示する)


Slide 15

Slide 15 text

気になる点(デメリット?)
 あくまで「Flutter」でビルドしている点
 事前にビルドしておけば、どんなパッケージとも組み合わせられる?
 
 Angularを組み合わせたサンプルは公式にある。
 
 ※詳細は未確認
 https://github.com/flutter/samples/tree/main/web_embedding/ng-flutter 


Slide 16

Slide 16 text

参考
 公式サンプル(場所が少し変わっていたので注意)
  https://github.com/flutter/samples/tree/main/web_embedding/element_embedding_demo 
 
 
 他
 
 https://medium.com/simform-engineering/element-embedding-in-flutter-web-ef764fc64410 
 
 https://medium.com/flutter-community/element-embedding-in-flutter-dda770dad792 
 
 https://geekyants.com/blog/flutter-element-embedding/ 


Slide 17

Slide 17 text

サンプルコード
 https://github.com/beeeyan/element_embedding_trial
 
 ※公式を真似ただけなので、公式のサンプルの方がより良いかとは思う。