Flutter 中 JavaScript(JS)与 Dart 双向通信实现方案

基于官方 webview_flutter 插件的通信方式

基于官方 webview_flutter 插件的通信方式

在 pubspec.yaml 中添加

添加 webview 包 方便后面使用,记得 pub get 更新

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter
  # 移动端 WebView 通信核心依赖
  webview_flutter: ^4.4.4
  # Web 平台 JS 通信依赖
  js: ^0.6.7

配置自己使用的 js 路径地址信息, 该地址位于项目根目录中添加对应 js 文件

yaml 复制代码
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  assets:
    - assets/js/xxx.js

静态 js 文件,建立通道

javascript 复制代码
function test(){
    if (window.FlutterJsChannel) {
        window.FlutterJsChannel.postMessage(realTimeData);
        console.log(realTimeData);
        // 新增:打印推送成功日志
        console.log("【JS 推送成功】:数据已发送给 Flutter");
    } else {
        // 新增:打印推送失败日志
        console.log("【JS 推送失败】:FlutterJsChannel 不存在");
    }
}

postMessage 通道的核心概念

  • postMessage 本质是 Flutter 为 WebView 提供的跨端通信接口,专门用于 JavaScript → Flutter 的数据传递(单向主动推送)。你可以把它理解成:
  • Flutter 在 WebView 里 "预埋" 了一个名为 FlutterJsChannel(你自定义的名称)的 "消息信箱";
  • JS 端只要往这个 "信箱" 里丢消息(调用 postMessage),Flutter 端的 onMessageReceived 回调就会立刻收到并处理。

WebView 加载的 HTML/JS 中,通过 window.通道名称.postMessage(数据) 发送消息

dart 文件 创建 web 交互 方法定义

通过 runJavaScript(jsCode); 调用项目 内部方法

dart 复制代码
import 'package:webview_flutter/webview_flutter.dart';
late WebViewController _webViewController;
_webViewController = WebViewController()
	..setJavaScriptMode(JavaScriptMode.unrestricted)
	..setBackgroundColor(Colors.white)
	..loadHtmlString("""<html><body></body></html>""")
	..addJavaScriptChannel(
		"FlutterJsChannel",
		// 实时接收 JS 传递的数据(持续回调,无需主动触发)
		onMessageReceived: (JavaScriptMessage message) {
		  print("object");
		  // 第一步:先打印日志,这是最直接的验证,无关 UI 更新
		  print("【通道回调触发】:收到数据 -> ${message.message}");
		  // print("【数据类型】:${message.message.runtimeType}");
		  _updateAnimeList(message.message);
	}
);

// 步骤 1:读取并加载 Assets 中的 JS 文件(核心:注入 JS 函数)
Future<void> _loadAssetsJsFile() async {
try {
  // ① 读取 Assets 中的 JS 文件(转为纯文本字符串)
  // 路径必须和 pubspec.yaml 中声明的一致(大小写敏感)
  String assetsJsContent = await rootBundle.loadString("assets/js/md5.js");

  // ② 执行该 JS 字符串,将函数注入 WebView 环境
  // 此时只是「导入」函数,并未调用具体方法,无返回值
  await _webViewController.runJavaScript(assetsJsContent);

  setState(() {
    _callResult = "Assets JS 文件加载完成(函数已注入),可调用具体方法";
    _callAssetsJsFunction();
    print(_callResult);
  });
} catch (e) {
  setState(() {
    _callResult = "加载 Assets JS 文件失败:$e";
  });
}
}

// 步骤 2:调用 Assets JS 文件中定义的具体方法
_callAssetsJsFunction() async {
	try {
	  // ① 编写 JS 代码,调用已注入的函数(来自 assets/js/demo.js)
	  String jsCode = """
	    test();
	  """;
	  // ③ 执行 JS 代码,触发函数调用
	   _webViewController.runJavaScript(jsCode);
	  // 新增:打印日志,确认 JS 指令发送成功
	  print("【Flutter】JS 执行指令已发送给 WebView");
	} catch (e) {
	  setState(() {
	    _callResult = "调用 Assets JS 函数失败:$e";
	  });
	}
}
  • WebViewController()
    • 创建一个 WebView 的控制器实例,用来管理 WebView 的所有行为(加载页面、JS 交互、样式设置等)。
  • ..setJavaScriptMode(JavaScriptMode.unrestricted)
    • 开启 WebView 的 JavaScript 支持:
    • JavaScriptMode.unrestricted:完全允许 JS 执行(默认是禁用的),这是 Flutter 和 JS 交互的前提。
    • 如果设为JavaScriptMode.disabled,则 WebView 中的 JS 代码无法运行,通信通道也会失效。
  • ..setBackgroundColor(Colors.white)
    • 设置 WebView 的背景颜色为白色(默认可能是透明或灰色),优化视觉效果。
  • ..loadHtmlString("""<html><body></body></html>""")
    • 加载一段空的 HTML 字符串到 WebView 中(也可以用loadUrl加载远程网页)。这里加载空页面,说明核心目的是通过 JS 通道接收数据,而非展示网页内容。
  • ..addJavaScriptChannel(...)
    • 这是核心逻辑:创建 Flutter 和 JS 之间的通信通道,实现JS 主动向 Flutter 发送数据:
    • "FlutterJsChannel":通道的唯一标识,JS 端必须通过这个名称调用(比如window.FlutterJsChannel.postMessage('要传递的数据'))。
    • onMessageReceived:回调函数,只要 JS 调用了postMessage,这个回调就会实时触发(也就是你注释里说的 "持续回调,无需主动触发")。
    • JavaScriptMessage message:回调的参数,message.message是 JS 传递的原始数据(字符串类型)。
  • 回调内的逻辑
    • print("【通道回调触发】:收到数据 -> ${message.message}"):打印 JS 传递的数据,用于调试验证。
    • _updateAnimeList(message.message):调用自定义方法处理数据(比如解析数据、更新动漫列表)。
    • 注释的setState:如果需要更新 Flutter 的 UI(比如把数据展示在页面上),必须用setState触发页面刷新。

项目启动类

csharp 复制代码
void main()
{
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

WidgetsFlutterBinding.ensureInitialized() 是 Flutter 应用的 "基础引擎初始化",为所有 Widget 和异步操作提供运行环境。

Web 平台 - Dart 与 JS 通信

@JS

@JS() 是 package:js 库提供的元注解(装饰器),作用是建立 Dart 代码和 JS 代码的映射关系。你可以把它理解成:给 Dart 代码贴一个 "标签",告诉 Dart 编译器 "这段代码要对应到 JS 中的某个东西"。

传递 Dart 函数给 JS(回调)

用 @allowInterop 注解(@JS() 配套),可以把 Dart 函数作为回调传给 JS。

  • @JS() 是 Dart 与 Web 端 JS 交互的核心注解,用于建立 Dart 代码和 JS 变量 / 函数 / 对象的映射关系。
  • 使用时必须导入 package:js,且被注解的成员需加 external 关键字。
  • 配套 @allowInterop 可实现 Dart 函数作为回调传给 JS,仅支持 Web 平台。
相关推荐
2401_895521347 小时前
SpringBoot Maven快速上手
spring boot·后端·maven
disgare7 小时前
关于 spring 工程中添加 traceID 实践
java·后端·spring
ictI CABL7 小时前
Spring Boot与MyBatis
spring boot·后端·mybatis
小江的记录本9 小时前
【Linux】《Linux常用命令汇总表》
linux·运维·服务器·前端·windows·后端·macos
yhole12 小时前
springboot三层架构详细讲解
spring boot·后端·架构
香香甜甜的辣椒炒肉12 小时前
Spring(1)基本概念+开发的基本步骤
java·后端·spring
白毛大侠13 小时前
Go Goroutine 与用户态是进程级
开发语言·后端·golang
ForteScarlet13 小时前
从 Kotlin 编译器 API 的变化开始: 2.3.20
android·开发语言·后端·ios·开源·kotlin
大阿明13 小时前
SpringBoot - Cookie & Session 用户登录及登录状态保持功能实现
java·spring boot·后端
Binary-Jeff13 小时前
Spring 创建 Bean 的关键流程
java·开发语言·前端·spring boot·后端·spring·学习方法