Flutter WebView与JS交互简易指南

简介: 本文采用Flutter官方WebView插件:https://pub.dartlang.org/packages/webview_flutter  WebView与JS互相调用是一个刚需,但是貌似现在大家写的文章讲的都不是很清楚,我这个简易指南简单粗暴地分为两部分:JS调用Flutter和Flutter调用JS,拒绝花里胡哨,保证一看就懂,一学就会。

本文采用Flutter官方WebView插件:https://pub.dartlang.org/packages/webview_flutter

  WebView与JS互相调用是一个刚需,但是貌似现在大家写的文章讲的都不是很清楚,我这个简易指南简单粗暴地分为两部分:JS调用FlutterFlutter调用JS拒绝花里胡哨,保证一看就懂,一学就会。

  开始之前先简单了解一下官方WebView所包含的API:

  • onWebViewCreated:在WebView创建完成后调用,只会被调用一次;
  • initialUrl:初始load的url;
  • javascriptMode:JS执行模式(是否允许JS执行);
  • javascriptChannels:JS和Flutter通信的Channel;
  • navigationDelegate:路由委托(可以通过在此处拦截url实现JS调用Flutter部分);
  • gestureRecognizers:手势监听;
  • onPageFinished:WebView加载完毕时的回调。

JS调用Flutter

  JS调用Flutter有两种方法:使用javascriptChannels发送消息使用路由委托(navigationDelegate)拦截url

方法1:使用javascriptChannels发送消息

  javascriptChannels参数可以传入一组Channels,我们可以定义一个_alertJavascriptChannel变量,这个channel用来控制JS调用Flutter的toast功能:

JavascriptChannel _alertJavascriptChannel(BuildContext context) {
    return JavascriptChannel(
        name: 'Toast',
        onMessageReceived: (JavascriptMessage message) {
          showToast(message.message);
        });
  }

WebView(
    avascriptChannels: <JavascriptChannel>[
        _alertJavascriptChannel(context),
    ].toSet(),
;

  在上面的代码中,我们定义了一个_alertJavascriptChannel变量,并给它起了个name叫Toast,这个name属性接收的是一个字符串,它代表了JS调用Flutter时,双方共同商定好了的一个协议,JS通过这个name去post对应的信息给Flutter(API为name.postMessage('xxxxxx'))。我们在网页部分写一个简单的button,点击后开始JS调用Flutter的逻辑:

<button onclick="callFlutter()">callFlutter</button>

function callFlutter(){
   Toast.postMessage("JS调用了Flutter");
}

  onMessageReceived为Flutter接收到了JS的消息之后的回调,我们可以通过message.message来获取JS发给我们的消息内容。JavascriptMessage类暂时只有一个String类型的message成员变量,所以如果需要传递复杂数据,可以通过传递json字符串来解决。

  代码重点:JavascriptChannel中的name要与JS中的name.postMessage()相对应!!

方法2:使用路由委托navigationDelegate拦截url

  navigationDelegate回调在每次网页路由地址发生变化的时候都会触发,因此我们可以拦截特定的url来实现JS调用Flutter。
同样的,我们在网页部分写一个简单的button,点击后跳转路由"js://webview?arg1=111&args2=222"。我们可以和客户端协商好一个scheme,比如这个例子里面就是js://webview,我们可以在query string上带上我们想要传递的参数:

<button onclick="callFlutter()">callFlutter</button>

function callFlutter(){
  /*约定的url协议为:js://webview?arg1=111&arg2=222*/
  document.location = "js://webview?arg1=111&args2=222";
}

  在Flutter端,我们就可以在navigationDelegate回调中拦截这个符合js://webviewscheme的路由地址了:

navigationDelegate: (NavigationRequest request) {
            if (request.url.startsWith('js://webview')) {
              showToast('JS调用了Flutter By navigationDelegate');
              print('blocking navigation to $request}');
              return NavigationDecision.prevent;
            }
            print('allowing navigation to $request');
            return NavigationDecision.navigate;
          },

  我们通过return不同的值,告诉WebView怎么处理这个路由:

  • NavigationDecision.prevent:阻止路由替换;
  • NavigationDecision.navigate:允许路由替换。

Flutter调用JS

  在WebView创建完成之后,我们可以拿到一个WebViewController,通过它的evaluateJavascript()方法,我们可以执行JS语句:

onWebViewCreated: (WebViewController webViewController) {
    _controller = webViewController;
},
······
floatingActionButton: FloatingActionButton(
        onPressed: () {
          _controller
              ?.evaluateJavascript('callJS("visible")')
              ?.then((result) {
                  // You can handle JS result here.
              });
        },
        child: Text('call JS'),
      ),
  <p id="p1" style="visibility:hidden;">
    Flutter 调用了 JS.
    Flutter 调用了 JS.
    Flutter 调用了 JS.
  </p>
  
function callJS(message){
  document.getElementById("p1").style.visibility = message;
}

  在上面的例子中,我们点击floatingActionButton后,就会去执行JS中的callJS()方法了,具体UI体现为:将隐藏的段落重新显示。evaluateJavascript()返回值是一个Future,因此我们可以接收JS给我们的返回值,返回值格式请阅读官方API注释。
这里要注意的是,evaluateJavascript()方法,Flutter建议我们在onPageFinished回调之后去执行,以保证所有的HTML都已经加载完毕了。因此在实际开发中,我这里展示的这种直接将onWebViewCreated中的controller赋值的方法是不可取的,应该是使用FutureBuilder之类的方式去实现比较优雅(我在Gist上有完整的例子,大家可以看下)。

源码

  注意:源码中的initialUrl测试地址请自己生成!



相关文章
|
1月前
|
小程序 JavaScript 前端开发
【微信小程序】--WXML & WXSS & JS 逻辑交互介绍(四)
【微信小程序】--WXML & WXSS & JS 逻辑交互介绍(四)
|
1月前
|
JavaScript 前端开发
javascript中的交互效果
javascript中的交互效果
|
2月前
|
前端开发 JavaScript
前端 JavaScript 与 HTML 怎么实现交互
前端 JavaScript 与 HTML 怎么实现交互
|
2月前
|
Rust 前端开发 JavaScript
Rust与JavaScript的跨语言交互:探索与实践
本文旨在探讨Rust与JavaScript之间的跨语言交互方法。我们将深入了解WebAssembly(Wasm)的角色,以及它如何使得Rust与JavaScript能够在Web应用中和谐共处。此外,我们还将介绍Rust与JavaScript的集成方式,包括Rust编译到Wasm、使用wasm-bindgen进行Rust与JavaScript的绑定,并通过实际案例展示如何实现两者之间的交互。
|
2月前
|
XML Android开发 数据格式
安卓和webview交互
安卓和webview交互
23 0
|
3月前
|
前端开发 JavaScript 定位技术
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较
33 0
|
3月前
|
存储 监控 前端开发
JavaScript手册:公司员工电脑监控软件前端交互的代码设计
在当今信息时代,随着公司对员工电脑活动的监控需求不断增加,前端交互的代码设计变得尤为关键。本手册将深入探讨JavaScript编写的公司员工电脑监控软件监控代码,着重介绍如何设计能够在不引起怀疑的情况下,实现对员工电脑活动的细致监控。
226 2
|
4月前
|
存储 JavaScript C#
【傻瓜级JS-DLL-WINCC-PLC交互】8.DLL读写WINCC连接的PLC数据
【傻瓜级JS-DLL-WINCC-PLC交互】8.DLL读写WINCC连接的PLC数据
32 0
【傻瓜级JS-DLL-WINCC-PLC交互】8.DLL读写WINCC连接的PLC数据
|
4月前
|
JavaScript C#
【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据
【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据
81 0
|
4月前
|
JavaScript C#
【傻瓜级JS-DLL-WINCC-PLC交互】6.​向PLC里面装载数据变量
【傻瓜级JS-DLL-WINCC-PLC交互】6.​向PLC里面装载数据变量
32 0