Flutter Web中如何从HtmlElementView获取数据及WebView嵌入问题
Flutter Web中HtmlElementView获取Daum地址数据的解决方案
在Flutter Web里用HtmlElementView嵌入Daum地址选择页时,无法直接复用App端WebView的JavascriptChannel机制,需要通过iframe的postMessage跨页面通信能力实现数据传递,具体实现如下:
核心实现思路
- 保留iframe实例引用,给全局
window添加消息监听,接收来自iframe内部的地址数据 - 等待iframe加载完成后,注入JS代码改写Daum地址选择页的回调逻辑,让选中地址后通过
postMessage把数据发送到父页面 - 解析接收到的消息数据,完成地址回调并关闭页面
修改后的完整代码
import 'package:flutter/material.dart'; import 'dart:ui' as ui; import 'dart:html' as html; import 'dart:convert'; class UserAddress3 extends StatefulWidget { const UserAddress3({Key? key}) : super(key: key); @override State<UserAddress3> createState() => _UserAddress3State(); } class _UserAddress3State extends State<UserAddress3> { html.IFrameElement? _iframeElement; @override void initState() { super.initState(); // 注册iframe视图工厂 ui.platformViewRegistry.registerViewFactory( 'html.iframeElement', (int viewId) { _iframeElement = html.IFrameElement() ..src = 'https://daum_postcode_mobile' ..style.width = '100%' ..style.height = '100%' ..style.border = 'none'; // 监听iframe加载完成事件,注入回调改写代码 _iframeElement!.onLoad.listen((_) => _injectDaumPostcodeCallback()); // 监听来自iframe的消息 html.window.addEventListener('message', _handleMessage); return _iframeElement!; }, ); } void _injectDaumPostcodeCallback() { // 注入JS代码:重写Daum地址选择的complete回调 final jsCode = ''' setTimeout(() => { // 保留原回调(如果存在) const originalComplete = window.daum?.Postcode?.complete; // 改写回调逻辑,发送数据到父页面 window.daum.Postcode.complete = function(data) { window.parent.postMessage(JSON.stringify(data), '*'); originalComplete && originalComplete(data); }; }, 1000); '''; // 创建script标签注入到iframe文档 final script = html.ScriptElement() ..type = 'text/javascript' ..text = jsCode; _iframeElement!.contentDocument!.body!.append(script); } void _handleMessage(html.Event event) { if (event is html.MessageEvent) { try { // 解析地址数据并返回上一页 final addressData = json.decode(event.data); Navigator.pop(context, addressData["address"]); } catch (e) { print('地址数据解析失败: $e'); } } } @override void dispose() { // 移除消息监听,避免内存泄漏 html.window.removeEventListener('message', _handleMessage); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('주소 검색'), backgroundColor: Colors.white, ), body: HtmlElementView( viewType: 'html.iframeElement', ), ); } }
关键细节说明
- 跨域消息传递:使用
window.parent.postMessage发送数据,这里用'*'作为目标源是因为Daum地址页允许跨域通信,若有固定域名可替换为具体域名提升安全性 - JS注入时机:通过
setTimeout延迟执行,确保Daum的地址选择脚本已加载完成 - 资源清理:在
dispose方法中移除消息监听,防止页面销毁后出现内存泄漏问题
内容的提问来源于stack exchange,提问作者Juda
相关产品推荐
相关产品推荐

