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

Flutter WebView与Vue.js网页通信postMessage空值报错问题

异常原因

这个报错是多个逻辑问题叠加导致的:

  • message.js中直接使用了未定义的userAgent变量,没有从window.navigator.userAgent取值,导致端环境判断逻辑完全失效。
  • 环境判断失效后代码走到else分支,尝试调用window.opener.postMessage,但WebView中加载的页面不存在通过window.open打开它的父窗口,window.opener值为null,对null调用postMessage方法就会抛出你看到的TypeError。
  • 桥接调用逻辑不匹配:你使用的webview_flutter插件注册的JavascriptChannel,在Android和iOS端都是统一挂载在页面对应的window对象下,直接通过注册时设置的name属性调用即可,你写的iOS端webkit消息处理逻辑是原生WKWebView的通信方式,不适用于这个Flutter插件场景。
  • 冗余错误代码:main.js中对普通工具对象调用Vue.use()是无效写法,Vue插件必须暴露install方法才能被Vue.use()注册,你写的message对象原本不满足插件要求。
修复方案

分别调整Web端和Flutter端代码即可:

Web端修改

  1. 重写message.js,修正环境判断逻辑,优先判断桥接对象是否存在(比UA判断更可靠),同时补全Vue插件需要的install方法:
const sendMessage = (message) => {
  // 正确获取UA做兼容判断
  const userAgent = window.navigator.userAgent.toLowerCase();
  // 优先判断Flutter注入的桥接对象是否存在
  if (window.WebViewBridge) {
    // 注意如果传对象需要先序列化,webview_flutter默认只支持字符串传递
    return window.WebViewBridge.postMessage(typeof message === 'string' ? message : JSON.stringify(message));
  }
  // 兼容原生iOS WKWebView场景,不需要可以删除
  if ((userAgent.indexOf('iphone') !== -1 || userAgent.indexOf('ipad') !== -1) && window.webkit?.messageHandlers?.webViewMessageHandler) {
    return window.webkit.messageHandlers.webViewMessageHandler.postMessage(message);
  }
  // 本地浏览器调试场景兜底
  console.log('非App WebView环境,消息内容:', message);
}

export default {
  // 补全install方法支持Vue.use注册
  install(Vue) {
    Vue.prototype.$sendMessage = sendMessage;
  },
  sendMessage
}
  1. 简化main.js,删掉多余的全局挂载代码:
import Vue from 'vue'
import App from './App.vue'
import message from './message'; 

Vue.config.productionTip = false
Vue.use(message);

new Vue({
  render: h => h(App)
}).$mount('#app')
  1. 修改App.vue的调用逻辑,直接使用Vue原型上挂载的方法,不需要重复引入message文件:
<template>
  <div class="main">
    <div class="btn" @click="toast()">communicate!</div>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    toast(){
      console.log("message to Flutter App!")
      this.$sendMessage("hello")
    }
  },
};
</script>
<style>
.main{
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: antiquewhite;
}
.btn{
  background-color: black;
  color: #fff;
  padding: 10px 20px;
  border-radius: 10px;
  cursor: pointer;
}
</style>

Flutter端修改

补全缺失的组件定义,在消息接收回调中加提示逻辑,注意Android端的网络配置:

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() => runApp(
  MaterialApp(
    title: 'Navigator',
    initialRoute: '/my',
    routes: {
      "/my":  (context) => MyApp(),
    },
  ),
);

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        // 不需要AppBar可以直接设为null
        appBar: const EmptyAppBar(), 
        body: WebView(
            initialUrl: "http://你电脑的局域网IP:8080/",
            javascriptMode: JavascriptMode.unrestricted,
            javascriptChannels: <JavascriptChannel>{
              _webToApp(context),
            }
        )
    );
  }
}

JavascriptChannel _webToApp(BuildContext context) {
  return JavascriptChannel(
      name: 'WebViewBridge',
      onMessageReceived: (JavascriptMessage result) {
        print('收到JS端消息: ${result.message}');
        // 用系统自带组件弹提示,不需要引入第三方库
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text("收到网页消息:${result.message}"))
        );
      });
}

// 补全你代码里缺失的EmptyAppBar定义
class EmptyAppBar extends AppBar {
  const EmptyAppBar({Key? key}) : super(
    key: key,
    elevation: 0,
    backgroundColor: Colors.transparent
  );
}
调试注意事项
  • 确保测试手机和运行前端服务的电脑在同一局域网下,Flutter代码里填写的IP是电脑的局域网IP,不要填localhost或者127.0.0.1,这两个地址指向手机自身。
  • Android端需要在AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET" />,同时在<application>标签添加android:usesCleartextTraffic="true",允许加载http明文地址。
  • webview_flutter 3.0及以上版本不需要手动修改UA,桥接对象会在页面加载时自动注入。

内容的提问来源于stack exchange,提问作者Yesterday BetterThan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:39:20