Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
FlutterをHTML elementに埋め込む
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
ken
July 15, 2023
Programming
1.4k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
FlutterをHTML elementに埋め込む
ken
July 15, 2023
More Decks by ken
See All by ken
Dart3を試す
masumitsu
0
570
Other Decks in Programming
See All in Programming
New "Type" system on PicoRuby
pocke
1
1k
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
210
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
280
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
2.3k
AI時代のUIはどこへ行く?その2!
yusukebe
22
7.5k
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
140
Webフレームワークの ベンチマークについて
yusukebe
0
180
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
220
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.3k
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
130
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
170
Featured
See All Featured
AI: The stuff that nobody shows you
jnunemaker
PRO
8
730
Git: the NoSQL Database
bkeepers
PRO
432
67k
A Modern Web Designer's Workflow
chriscoyier
698
190k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
620
[SF Ruby Conf 2025] Rails X
palkan
2
1.1k
30 Presentation Tips
portentint
PRO
1
330
Design in an AI World
tapps
1
250
How to Ace a Technical Interview
jacobian
281
24k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
How GitHub (no longer) Works
holman
316
150k
First, design no harm
axbom
PRO
2
1.2k
Transcript
FlutterをHTML elementに 埋め込む 2023/07/14 第4回 FlutterGakkai
自己紹介 • kenma: 益満 健 (Masumitsu Ken) • 株式会社ディー・エヌ・エー ◦
日比谷音楽祭2023アプリ作成 (Flutter) • Twitter: @kenma • Qiita: @kenma
なぜ埋め込みたい?? • 既存のWebページがあるから ◦ 例えば、WordPressで作られたサイトに、 Flutterを埋め込む • SEOのため ◦ Flutter
for Webは動的コンテンツなので SEOに不向き ◦ HTML/JSでSEO対策をして、コアの部分は Flutterを埋め込む • 高速化のため ◦ (Flutter WASMで)Webの一部をFlutterに置き換えることにより高速化。(?) • 従来は IFrameを利用することで埋め込みができていた。 ◦ が、IFrameの内外間の相互通信が複雑だった。
試してみる!
プロジェクトセットアップ • flutter 3.10.5 • js 0.67 flutter create sample
--platforms web cd sample flutter pub add js flutter run -d chrome
<!-- 3. #flutter_targetのスタイルを指定。--> <link rel="stylesheet" type="text/css" href="css/style.css" /> </head> <body>
<script> window.addEventListener('load', function(ev) { _flutter.loader.loadEntrypoint({ serviceWorker: { serviceWorkerVersion: serviceWorkerVersion, }, onEntrypointLoaded: function(engineInitializer) { engineInitializer.initializeEngine({ // 2. HTMLエレメントを指定 hostElement: document.querySelector("#flutter_target"), }).then(function(appRunner) { appRunner.runApp(); }); } }); }); </script> <section class="contents"> <div>この下にFlutterアプリを表示する。</div> <article> <!-- 1. flutterアプリを表示するHTMLエレメント --> <div id="flutter_target" class="center"></div> </article> </section> </body> </html> index.htmlの修正 1. Flutterアプリを表示するHTMLエレメント (※)を準備 ◦ id = flutter_target 2. initializeEngineの引数 hostElement に HTMLエレメント(※)を指定 3. HTMLエレメント(※)にCSSでスタイルを当 てるためにcssを読み込む
css/style.cssの作成 1. #flutter_targetのwidth, heightを指定 ◦ 忘れると表示されない! /** 重要!! */ #flutter_target
{ border: 1px solid #aaa; width: 320px; height: 480px; border-radius: 0px; transition: all 150ms ease-in; } .center { margin: auto; width: 50%; }
実行
おわり
埋め込むだけなら <iframe> でもできていた WebアプリとFlutter間でインタラクションをしたい! • Webアプリが主で、Flutterアプリ側が従という関係。 • なので、したいことは、 a. Webアプリから、Flutterアプリを操作する。
b. Webアプリから、Flutterアプリのイベントを検知する。
埋め込むだけなら <iframe> でもできていた WebアプリとFlutter間でインタラクションをしたい! • Webアプリが主で、Flutterアプリ側が従という関係。 • なので、したいことは、 a. Webアプリから、Flutterアプリを操作する。
→ JSからFlutterのメソッドを呼ぶ。 b. Webアプリから、Flutterアプリのイベントを検知する。 → JSからFlutterにcallback関数を渡すメソッドを呼ぶ。 ⇒ どちらもJSから、Flutterのメソッドを呼び出せればいい
作りたいもの どちらも同じカウンタ値を表示 どちらのボタンでも、 カウンタをインクリメントできる
FlutterのメソッドをJSにExportする
main.dart • JS側にExportするクラスに@JSExportアノテー ションをつける。 ◦ クラスの全メソッドがExportされる。 • createDataExport()関数で、オブジェクトをJS からアクセスできる形にラップする •
allowInteropは使わなくてよくなった • js_utilを使って、JSコード呼び出し ◦ setProperty() ◦ callMethod() import 'package:js/js.dart' as js; import 'package:js/js_util.dart' as js_util; // _MyHomePageState を JS側にExport可能にする。 @js.JSExport() class _MyHomePageState extends State<MyHomePage> { int _counter = 0; @override void initState() { super.initState(); // _MyHomePageStateオブジェクトを、JS側にExportする final export = js_util.createDartExport(this); // JS側の globalThis(ブラウザの場合はwindow)の _appStateプロパ ティとして、 // export (_MyHomePageState) をセットする。 js_util.setProperty(js_util.globalThis, '_appState', export); // JS側の globalThisの_stateSetメソッドを引数無しで呼び出す。 js_util.callMethod<void>(js_util.globalThis, '_stateSet', []); }
index.html (function () { // _stateSet関数作成 window._stateSet = function ()
{ console.log('_stateSet function is called') // _appStateプロパティの値を取得 let appState = window._appState; console.log('_appState property is ', appState); }; }()); <!-- js/js-interop.js の読み込み --> <script src="js/js-interop.js" defer></script> </head> • js/js-interop.js を追加 js/js-interop.js • window._stateSet関数の作成 ◦ js_util.callMethod(, _stateSet,) で、呼ば れる
実行 _MyHomePageStateの全プロパティがExportさ れている。
main.dart • JS側にExportするメソッドに@JSExportアノ テーションをつける。 ◦ 指定したメソッドのみ JS側にExportされる ◦ @JSExport(‘foo’) と名前を指定すると、
JSからそ の名前でExportする。 //@js.JSExport() //コメントアウト class _MyHomePageState extends State<MyHomePage> { int _counter = 0; @override void initState() { super.initState(); // _MyHomePageStateオブジェクトを、JS側にExportする final export = js_util.createDartExport(this); // JS側の globalThis(ブラウザの場合は、window)に プロパティ (_appState)、値 (export)をセットする。 js_util.setProperty(js_util.globalThis, '_appState', export); // JS側の globalThisの_stateSetメソッドを引数無しで呼び出す。 js_util.callMethod<void>(js_util.globalThis, '_stateSet', []); } @js.JSExport('inc') // inc という名前でExport void _incrementCounter() {
実行 incメソッドのみExportされている。
HTML/JSからFlutterのコードを呼ぶ HTML/JSから、Flutterのカウンター値を増加させる。
main.dart • JS側にExportするメソッドに @js.JSExportアノテーションをつ ける • callback関数を受け取るメソッドも 特殊なことはしない。 // @js.JSExportしない
class _MyHomePageState extends State<MyHomePage> { @js.JSExport() void _incrementCounter() { setState(() { _counter++; // 変更を通知 _streamController.add(null); }); } @js.JSExport() int get count => _counter; // callback関数を受け取る関数を Exportする @js.JSExport() void addHandler(void Function() handler) { _streamController.stream.listen((event) { handler(); }); }
index.html • カウンター機能を追加 ◦ カウンター値表示 ◦ インクリメントボタン <section class="contents"> <aside
id="demo_controls"> <fieldset id="interop"> <legend>JS Interop</legend> <!--カウンター値を表示 --> <label for="value"> Value <input id="value" value="" type="text" readonly /> </label> <!--インクリメントボタン --> <input id="increment" value="Increment" type="button" /> </fieldset> </aside> <article> <!-- 1. flutterアプリを表示するHTMLエレメント --> <div id="flutter_target" class="center"></div> </article> </section>
js/js-interop.js • インクリメントボタンを押したら、 Flutterの_incrementCounter()を 呼び出す。 • Flutterのカウンタが更新したら、 updateStateがコールバックされ る。 (function
() { window._stateSet = function () { // js_util.setProperty() でセットした、_appStateプロパティの取得 const appState = window._appState; // インクリメントボタンのHTMLエレメント取得 const incrementButton = document.querySelector("#increment"); incrementButton.addEventListener("click", (event) => { // Flutterの_MyHomePageState._incrementCounter()の呼び出し appState._incrementCounter(); }); // カウンター値表示エリアの HTMLエレメント取得 const valueField = document.querySelector("#value"); const updateState = function () { // Flutterの_MyHomePageState.count の呼び出し valueField.value = appState.count; }; updateState(); // Flutterの_MyHomePageState.addHandlerを呼び出す。 // callback関数 updateStateを与える。 appState.addHandler(updateState); }; }());
実行
まとめ • FlutterをHTML elementに埋め込める。 • FlutterとHTML/JS間でインタラクションが簡単に
まとめ • FlutterをHTML elementに埋め込める。 • FlutterとHTML/JS間でインタラクションが簡単に • しかしながら、実プロダクトで利用するには時期尚早 ◦ Reactアプリに埋め込む場合、実際には大変。ドキュメントが必要だが、まだない。
▪ 参照 https://github.com/flutter/flutter/issues/123940 ◦ JSからDartのAsync関数を呼べない。 ▪ 参照 https://tinyurl.com/29c7fb8c • おまけ ◦ 今日見せたコード:https://github.com/kenmasumitsu/flutter-web-enbedding