Flutter嵌入webview并与vue进行双向通信

最近在做一个将h5嵌入flutter中的项目,特此记录一下,如有不对之处,希望大家多多指正。

本篇将围绕以下两点:

  1. 插件的选择与使用
  2. flutter与vue之间的双向通信

一、插件的选择与使用
目前flutter使用的比较多webview插件的主要有以下三个:

WebView({
    Key key,
    this.onWebViewCreated,           	   	          //WebView创建完成之后的回调
    this.initialUrl,                               	  //初始化 URL
    this.javascriptMode = JavascriptMode.disabled,    //JS执行模式,默认是不调用
    this.javascriptChannels,                          //JS可以调用Flutter 的通道
    this.navigationDelegate,            			  //路由委托,可以使用它执行拦截操作
    this.gestureRecognizers,          				  //手势相关
    this.onPageStarted,                 			  //开始加载页面回调
    this.onPageFinished,                              //页面加载完成的回调
    this.onWebResourceError,                          //资源加载失败回调
    this.debuggingEnabled = false,
    this.gestureNavigationEnabled = false,
    this.userAgent,                      			  //用户代理
    this.initialMediaPlaybackPolicy =
        AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
  })

作为官方提供的插件,webview_flutter还是相对比较好用的,不过在开发的过程中发现其在国内某些品牌的手机上运行时,由于国内厂商对键盘进行魔改(比如安全键盘),会出现无发调出或者虚拟键盘闪烁后崩溃的问题,详情见官方issue

再看flutter_webview_plugin,其提供的WebviewScaffold组件构造函数如下:

WebviewScaffold({
    Key key,
  this.appBar,
    @required this.url,           //String 加载的URL
    this.headers,                 //添加头部
    this.withJavascript,		  //bool 是否开启Javascript
    this.clearCache,			  //bool 清理缓存
    this.clearCookies,            //bool 清理cookies
    this.enableAppScheme,
    this.userAgent,                //String userAgent
    this.primary = true,
    this.persistentFooterButtons,
    this.bottomNavigationBar,      //Widget 底部的bar
    this.withZoom,                 //bool 是否允许缩放
    this.withLocalStorage,         //bool 是否开启本地缓存
    this.withLocalUrl,             //bool
    this.scrollBar,                //bool 是否显示scrollBar
    this.supportMultipleWindows,
    this.appCacheEnabled,          //bool 是否开启缓存
    this.hidden = false,		   //bool 是否隐藏
    this.initialChild,			   //初始化的child,如果hidden = true 显示Widget
    this.allowFileURLs,  		   //bool 是否允许请求本地的FileURL
    this.resizeToAvoidBottomInset = false,
    this.invalidUrlRegex,
    this.geolocationEnabled
    this.debuggingEnabled = false,
    this.ignoreSSLErrors = false,
  }) 

flutter_webview_plugin目前是由Flutter社区进行维护,易用程度目前高于webview_flutter 。特性是基于原生 WebView 封装的 Flutter 插件,将原生的一些基本使用 API 封装好提供给 Flutter 调用,因此并不能内嵌于 Flutter Widget 树中。

在比较两个插件的优劣之后,我在项目中选择了flutter_webview_plugin进行开发。

简单用法如下:
Flutter代码

class Webview extends StatefulWidget {
  @override
  WebViewState createState() => WebViewState();
}

class WebViewState extends State<Webview> {

  var _resultInfo = 'Hello,Vue!';
  FlutterWebviewPlugin flutterWebViewPlugin = new FlutterWebviewPlugin();

  @override
  Widget build(BuildContext context) {
    return WebviewScaffold(
      //要打开的网址,此处以百度为例
      url: 'https://www.baidu.com/',
      javascriptChannels: <JavascriptChannel>[
        JavascriptChannel(
            name: 'getInfoFromVue',
            onMessageReceived: (JavascriptMessage message) {
              print("收到的参数传入:" + message.message); //String Hello,Flutter
              //通过evalJavascript()方法调用vue挂载到window的方法
              flutterWebViewPlugin
                  .evalJavascript("window.getInfoFromFlutter('$_resultInfo')")
                  .then((result) {})
                  .catchError((onError) {});
            }),
      ].toSet(),
    );
  }
}

JavascriptChannel里的name需要和web端约定好,前端开发通过约定好的name,比如此处的getInfoFromVue,调用postMessage()方法向Flutter传递参数。

Vue代码:

<template>
 <div>
      获取到的Flutter传入信息: <span>{{ infoFromFlutter }}</span>
</div>
</template>
<style scoped>
</style>

<script>
export default {
  name: "flutter",
  data: function() {
    return {
      infoFromFlutter: "",
    };
  },
  mounted: function() {
  //将getInfoFromFlutter()方法挂载到window以供给Flutter调用
    window["getInfoFromFlutter"] = info => {
      this.getInfoFromFlutter(info);
    };
	getInfoFromVue.postMessage("Hello,Flutter");
  },
  methods: {
    getInfoFromFlutter(info) {
     this.infoFromFlutter = info;
    }
  }
};
</script>

最后,在Widget销毁之前将flutterWebViewPlugin 销毁掉。

@override
  void dispose() {
    flutterWebViewPlugin.dispose();
    super.dispose();
  }
Logo

前往低代码交流专区

更多推荐