Upgrade to Pro — share decks privately, control downloads, hide ads and more …

div要素の中に、Flutterを埋め込んでみよう

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 div要素の中に、Flutterを埋め込んでみよう

FlutterのElement Embeddingを試してみた。
勉強会の資料。

Avatar for beeeyan

beeeyan

May 28, 2023
Tweet

More Decks by beeeyan

Other Decks in Technology

Transcript

  1. Element Embeddingとは?
 Element Embedding : 要素埋め込み
 
 Flutterの文脈においては Widgetを標準的なウェブの<div>に追加できる。 この方法で統合されると、Flutterは単にウェブコンポーネントに変わり、

    DOMとシームレスに統合される。 ただ、<div>の中に表示されるだけではなく、JavaScriptなどで状態を操作できる。 https://www.youtube.com/watch?v=PAOAjOR6K_Q&t=199s
  2. <script> window.addEventListener('load', function(ev) { ・・・省略・・・ }); </script> ↓  <div id="flutter_target"></div>

    ・・・省略・・・ <script> 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(); }, }); }); </script> プロジェクト作成後、 web/index.htmlを書き換え flutter_targetのセレクタを追加 デフォルトのloadEntrypointの記述を 変更してhostElementを追加
  3. 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<MyApp> { // 調査 final _streamController = StreamController<void>.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<void>(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」する。
  4. main.dart (2/2) final _streamController = StreamController<void>.broadcast(); @js.JSExport() void increment() {

    setState(() { _counterScreenCount++; _streamController.add(null); }); } @js.JSExport() void addHandler(void Function() handler) { _streamController .stream.listen((event) { handler(); }); } StreamController<T>.broadcast 複数のリスナーが同時にデータを受け取ることができるスト リーム 変更をHTML・JavaScript側に反映させるた め。 ※反映処理のcallbackを受け取る部分は、 main.dartのaddHandlerに処理がある。
  5. 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を引数に入れる。
  6. 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上のボタンを押下した際、
 何が起きているか?
 
 

  7. 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部分は自動で領域を持たな い。 (自力で実装しようとすると引っかかるかも)
  8. Element Embeddingの利点は?
 Flutter Webの弱点部分を組み合わせを解消するアプローチ
 • SEO
 • (初期読み込みなど)スピード
 その他
 •

    Flutterで既に作成したWidgetをWebでも利用したい。
 • モバイルアプリの画面をWebで表示してみたい。
 (スクレイピングさせたくない要素をFlutterで表示する)