Flutter Web中Dart与JavaScript双向通信及状态监听方案咨询
解决方案
首先纠正认知误区
你开发的是Flutter Web应用,本身运行在浏览器环境,完全不需要用webview_flutter这类移动端WebView嵌套插件,这类插件本身就是为移动端原生应用设计的,不支持Web平台,你直接用Flutter官方提供的dart:js、dart:js_util、dart:html库就能实现所有需求,无需任何第三方依赖。
问题1:Flutter与JS双向通信实现(无需读取DOM元素)
1.1 Flutter主动传值给JS
你不需要让JS读取HTML输入框的值,直接改造JS函数,让它支持接收入参即可:
// 修改script.js中的createRoom、joinRoom函数,去掉DOM读取逻辑,改为接收参数 function createRoom(roomInput) { console.log("Creating Room") // 直接用传进来的参数,不需要读document.getElementById if (roomInput.trim() === "") { alert("Please enter room number") return; } room_id = PRE + roomInput + SUF; // 原有后续逻辑不变 } function joinRoom(roomInput) { console.log("Joining Room") if (roomInput.trim() === "") { alert("Please enter room number") return; } room_id = PRE + roomInput + SUF; // 原有后续逻辑不变 }
Flutter侧直接传递自己管理的变量值即可,比如你用Flutter的TextField输入房间号,直接传控制器的值:
import 'dart:js' as js; final _roomController = TextEditingController(); // 创建房间按钮点击逻辑 void _handleCreateRoom() { js.context.callMethod('createRoom', [_roomController.text]); }
1.2 JS侧状态变化主动通知Flutter
你只需要在Flutter侧把回调方法注册到全局window对象上,JS侧触发对应回调即可实现状态监听:
第一步,Flutter侧注册回调:
import 'dart:js' as js; bool _isScreenSharing = false; String? _currentRoomId; @override void initState() { super.initState(); // 注册监听屏幕共享状态变化的回调 js.context['onScreenSharingStateChange'] = (bool isSharing) { setState(() { _isScreenSharing = isSharing; }); }; // 注册监听房间连接成功的回调 js.context['onRoomConnected'] = (String roomId) { setState(() { _currentRoomId = roomId; }); }; // 注册监听通知消息的回调 js.context['onNotify'] = (String msg) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); }; }
第二步,修改JS代码,在状态变化位置触发回调:
// startScreenShare 中屏幕共享开启后加一行 screenSharing = true window.onScreenSharingStateChange?.(true) // 新增 // stopScreenSharing 中屏幕共享关闭后加一行 screenSharing = false window.onScreenSharingStateChange?.(false) // 新增 // peer.on('open') 回调中加一行 notify("Waiting for peer to join.") window.onRoomConnected?.(room_id) // 新增 // notify 函数中加一行,把通知同步到Flutter侧 notification.hidden = false window.onNotify?.(msg) // 新增
通过这种方式,JS侧的所有状态变化都可以主动同步到Flutter,完全不需要依赖DOM元素。
问题2:WebRTC页面嵌入Flutter Web实现
你不需要用任何第三方HTML渲染插件,有两种成熟方案可选:
方案1:直接复用现有HTML文件,用IFrame嵌入
把你现有的webRTC.html、script.js、styles.css都放到Flutter项目的web根目录下,然后用HtmlElementView嵌入IFrame即可:
import 'dart:html' as html; import 'dart:ui_web' as ui_web; import 'package:flutter/material.dart'; class WebRtcPage extends StatefulWidget { const WebRtcPage({super.key}); @override State<WebRtcPage> createState() => _WebRtcPageState(); } class _WebRtcPageState extends State<WebRtcPage> { @override void initState() { super.initState(); // 注册IFrame视图 ui_web.platformViewRegistry.registerViewFactory( 'webrtc-iframe', (int viewId) => html.IFrameElement() ..src = 'webRTC.html' ..style.border = 'none' ..width = '100%' ..height = '100%', ); } @override Widget build(BuildContext context) { return const Scaffold( body: HtmlElementView(viewType: 'webrtc-iframe'), ); } }
如果需要调用IFrame内部的JS方法,只需拿到IFrame的contentWindow对象即可:
final iframe = html.document.querySelector('iframe') as html.IFrameElement; iframe.contentWindow?.callMethod('createRoom', [_roomController.text]);
方案2:全Flutter重写UI,JS只保留PeerJS逻辑
把原来HTML里的视频、按钮等UI元素全部用Flutter Widget重写,script.js只保留PeerJS的核心逻辑,不涉及任何DOM操作,这种方案体验更符合Flutter设计规范,维护成本更低。
内容的提问来源于stack exchange,提问作者Mithson

