You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web中如何从HtmlElementView获取数据及WebView嵌入问题

Flutter Web中HtmlElementView获取Daum地址数据的解决方案

在Flutter Web里用HtmlElementView嵌入Daum地址选择页时,无法直接复用App端WebView的JavascriptChannel机制,需要通过iframe的postMessage跨页面通信能力实现数据传递,具体实现如下:

核心实现思路

  1. 保留iframe实例引用,给全局window添加消息监听,接收来自iframe内部的地址数据
  2. 等待iframe加载完成后,注入JS代码改写Daum地址选择页的回调逻辑,让选中地址后通过postMessage把数据发送到父页面
  3. 解析接收到的消息数据,完成地址回调并关闭页面

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:52:21