Flutter Web 的资料真的是太少了啊,可以说是几乎没有。
Flutter Web 很多库基本都用不了。比如 WebView 的库,与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 的代码里:
方法如下:
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 的项目中。
关键点如下:
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 打包
2.2 将这些文件复制
2.3 将关键文件复制到 Flutter 项目
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 的交互。列出关键点记录,以便后续使用。
不仅单单是交互。
以此方式,还可以弥补一些 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