Flutter Web 很多库基本都用不了。比如 WebView 的库,与JS交互,使用原生的方法根本走不通。

Flutter Web 与 React 或 JS 通信交互

浏览器的项目还是要用前端JS的方式解决。经过了一通折腾,皇天不负苦心人,终于是把路走通了。

目录

  • 1. 与原生JS交互
  • 1.1 Flutter 调用 Js;
  • 1.2 Js 调用 Flutter;
  • 2. 与React交互
  • 2.1 Flutter 调用 React 的 Js 方法;
  • 2.2 React 调用 Flutter 的方法。

先引入 Flutter 的 JS 库:https://pub.dev/packages/js

dependencies:

js: ^0.6.7

一、与原生JS交互

1. Flutter 调用 Js

1.1 先在 HTML 提供一个 JS 方法:

js 的代码可以写在 index.html 的代码里:

Flutter Web 与 React 或 JS 通信交互

方法如下:

function getPersonInfo() {

const Person = {

name: 'John',

sex: 'women',

age: 36,

}

const jsonString = JSON.stringify(Person)

return jsonString;

}

1.2 在 Flutter 调用刚才的 JS 方法:

import 'dart:convert';

import 'package:flutter/material.dart';

import 'dart:js' as js;

class MyHomePage extends StatefulWidget {

const MyHomePage({Key? key, required this.title}) : super(key: key);

final String title;

@override

State<MyHomePage> createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: ElevatedButton(

child: const Text("调用js代码"),

onPressed: () {

// Flutter Web 调用 Js

var personInfo = js.context.callMethod('getPersonInfo');

print("personInfo is $personInfo");

},

)

);

}

}

至此,把 Flutter Web 项目运行一下,就可以在控制台看到运行结果。

非常简单。

2. Js 调用 Flutter 方法

先通过 Flutter 在 js 的 window 中注入一个方法,然后在 js 中调用这个方法。

2.1 先在 Flutter 提供一个方法(详见注释):

import 'dart:convert';

import 'package:flutter/material.dart';

import 'dart:js' as js;

class MyHomePage extends StatefulWidget {

const MyHomePage({Key? key, required this.title}) : super(key: key);

final String title;

@override

State<MyHomePage> createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

// Toast 显示提示信息 - 提供给 JS 的方法

void toastMsg(String msg) {

print("address: $msg");

MyUtils.showToast(msg);

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: ElevatedButton(

child: const Text("调用js代码"),

onPressed: () {

// 给 JS 提供一个方法。 js 通过 window 调用

js.context["toastMsg"] = toastMsg;

// Flutter Web 调用 Js

js.context.callMethod('showVersion');

},

)

);

}

}

2.2 Js端的代码:

function showVersion() {

// 调用 Flutter 提供的方法

window.toastMsg("当前版本号为:1.0.0");

}

至此,就实现了 Flutter 与 原生JS 的彼此交互。

原生JS基本只能实现最基础的逻辑,只掌握到这一步几乎毫无意义。目前绝大多数的项目都是 React 或 Vue 框架写的,React 的方法与原生JS还是有一些区别。接下来看一下与 React 的方法交互。

二、Flutter 与 React 交互

学习了上面的方法之后,应该已经明白了其中的原理。 真正做的时候,就会发现有一个难点:React框架打包之后,会对之前的JS方法名进行压缩处理,之前的方法名就变了,会 not found.所以,这里主要处理的就是 React 打包之后如何调用原始的方法。

上面已经知道如何互相交互了,这里就简单点,只列出关键点。

1. 在 React 中编写方法供 Flutter调用

React 可以做一些自己业务,最终打包,将打包之后的项目移至 Flutter Web 的项目中。

关键点如下:

Flutter Web 与 React 或 JS 通信交互

window自定义声明:

declare global {

interface Window {

toastMsg: Function;

}

}

关键方法:

const getAddress = async () => {

// ……

// 网络请求

// ……

const ads = “请求结果”;

setAddress(ads);

if (typeof window["toastMsg"] === "function") {

window.toastMsg(address);

}

return address ? address : “未登录”;

};

// 提供给 Flutter 的方法

window["getMyAddress"] = async () => {

return await getAddress();

};

2. 将 React 打包,把关键信息复制到 Flutter Web 项目中

2.1 React 打包

Flutter Web 与 React 或 JS 通信交互

2.2 将这些文件复制

Flutter Web 与 React 或 JS 通信交互

2.3 将关键文件复制到 Flutter 项目

Flutter Web 与 React 或 JS 通信交互

2.4 在 Flutter 中调用方法

@JS()

external getMyAddress();
// 暴露给JS的方法

void toastMsg(String msg) {

print("address: $msg");

MyUtils.showToast(msg);

}

Widget buildMine() {

return Container(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

TextButton(

onPressed: () {

// 将方法暴露给 js 的 window

js.context["toastMsg"] = toastMsg;

// 调用 JS 方法

var personInfo = js.context.callMethod('getMyAddress');

print("getAddress is $personInfo");

},

child: Text("js2PersonInfo"),

),

SizedBox(height: 20),

TextButton(

onPressed: () async {

// 调用Js的方法

try {

var promise = getMyAddress();

var result = await promiseToFuture(promise); // 第三个坑

print("getAddress is $result");

} catch (e) {

print("getDeviceInfo错误信息是 $e");

}

},

child: Text("getMyAddress"),

),

SizedBox(height: 20),

],

),

);

}

注意:

Flutter Web 与 React 或 JS 通信交互

至此,就实现了 Flutter Web 与 React 的交互。列出关键点记录,以便后续使用。

不仅单单是交互。

以此方式,还可以弥补一些 Flutter 非常大的一个劣势:网页首次打开,非常缓慢。

可以使用 React 实现一些动画,或者加载初始的界面,Flutter也会在同步加载。

结束。

如果有什么错误,或者有更好的实现方式,欢迎讨论。

参考:

flutter web 与 js 通信: https://juejin.cn/post/7173627056205496333

flutter web 与 js Promise 通信: https://juejin.cn/post/7173990644405239838

多终端自定义window方法: https://juejin.cn/post/6976654060430557220#heading-3

本文转载自:时光·李记