Flutter中加载web页并与web js通信

1,536 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

  • 在App中我们避免不了部分动态页面使用web形式的进行展示,但是Flutter并不像原生那样有现成的webView控件来给我们使用,这时候就需要一个官方维护的第三方的插件webview_flutter: ^2.8.0来进行展示,截止目前官方已更新至3.0.2,当然社区也有其他web的插件,选择这个是因为他是google官方维护的,所以不用担心停止维护而出现一些问题。

加载web页面

  • 构造方法
const WebView({
  Key? key,
  this.onWebViewCreated,// webview创建完毕回调
  this.initialUrl,//加载的url
  this.javascriptMode = JavascriptMode.disabled,//js执行模式 默认不执行js 
  this.javascriptChannels,//与js通信方法
  this.navigationDelegate,//路由委托 可执行拦截url操作
  this.gestureRecognizers,//执行手势操作相关
  this.onPageStarted,//页面开始加载回调
  this.onPageFinished,//页面加载完毕回调 可在此回调设置web title
  this.onProgress,//加载进度
  this.onWebResourceError,//web加载失败回调
  this.debuggingEnabled = false,//是否启用调试模式 默认不启用
  this.gestureNavigationEnabled = false,//指示水平滑动手势是否会触发前向列表导航 这个只在iOS生效
  this.userAgent,//设置用户代理 iOS 9之前不支持
  this.zoomEnabled = true,//是否支持缩放 iOS需要设置支持js调用
  this.initialMediaPlaybackPolicy =
      AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,//web中媒体是否自动播放 有两个枚举值
  this.allowsInlineMediaPlayback = false,//是否允许在iOS上在线播放HTML5视频,Android默认允许
 this.backgroundColor,//设置背景色 默认透明

一般我们都会写一个通用的web页面来加载,上面方法按需求引入即可,需要注意的是有部分字段是在iOS上需要特殊处理,比如如果需要支持缩放模式,iOS上必须要设置javascriptMode = JavascriptMode.unrestricted;支持js调用才行。

与Web通信

  • 上面我们看到有一个参数是与js通信的相关方法javascriptChannels,接下来我们就看看这个方法怎么和web进行通信的。进行两种情况说明: 1、Flutter如何调用Js的方法并获取返回值
    首先在构造函数 onWebViewCreated(controller)回调中我们获取webView控制器,使用它我们可以获取title等关键信息的值并可以掉用js中的方法。
onWebViewCreated: (controller) {
  _webViewController = controller;
},

然后在我们需要调用js的地方掉用下面方法返回一个Future<String>结果。比如js中有一个hello方法,接受一个参数,返回一个json串,我们就可以用下方这个方法来掉用js中的方法。

await _webViewController?.runJavascriptReturningResult("window.hello('params')");

当然如果不需要返回值直接调用下面第二个方法就行。

image.png

2、Web中如何调用Flutter中的方法
还是在构造函数中我们可以看到有个javascriptChannels方法,web调用flutter方法就在这里进行,我们看到javascriptChannels是一个 Set<JavascriptChannel> 集合,也就是说每一个 JavascriptChannel就代表一个js访问flutter的通道,我们可以在这里定义我们的flutter方法。

final Set<JavascriptChannel>? javascriptChannels;

具体使用:JavascriptChannel构造一共有以下两个字段。

JavascriptChannel(
    name: "方法名",//务必跟js端一样才行
    onMessageReceived: (JavascriptMessage message) {
    // message.message;是js向我们传递的参数 我们就可以根据参数来执行我们的逻辑。
    }),

具体用法:通过调用 postMessage 方法传递参数,

// name跟flutter保持一致 调用postMessage方法传递参数。
name.postMessage('Hello FLutter');

查了下资料,这里如果js端想要返回结果是无法直接返回的,因为这个方法的返回时 void,所以如果js端需要返回值,就需要我们在回调中主动调用js发送消息了。

image.png

总结

在Fluter中加载WebView还是需要依赖原生WebView引擎来进行渲染,可见Flutter对于WebView并没有自己渲染引擎,根据不同的平台来调用不同的Web引擎来进行渲染,与js互相通信的设计来说使用还是非常方便的,突然有个问题: 目前Flutter支持Web开发,虽然还不完善,如果Flutter应用镶嵌的Web页面也是Flutter开发的,这样的话还掉用原声渲染引擎的话是不是就多此一举了?还是Flutter以后会针对web出一个自己的渲染引擎?