FlutterWeb 和 WebView 原生交互调用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FlutterWeb 和 WebView 原生交互调用相关的知识,希望对你有一定的参考价值。

参考技术A 需要创建两个工程,一个是FlutterWeb工程最终打包成Web页面,一个是Flutter原生工程承载一个WebView用来加载Web页面。这样做的好处在于只需要一种语言开发iosandroid不用对接两次,可以直接使用社区Flutter原生工程的插件,只需要封装给Web调用。

FlutterWeb工程pubspec.yaml添加依赖

Flutter原生工程pubspec.yaml添加依赖

创建一个 toast_channel.dart,定义一个类实现 javascriptChannel 重写name指定channel名称和onMessageReceived指定调用函数

在WebView的 javascriptChannels 配置上定义的Channel

创建一个 native_channel.dart ,定义一个外部函数通过 @JS("调用的channel和函数名") 注解指定调用的原生函数(JavascriptChannel固定名称为postMessage)

需要使用的地方直接调用

创建一个 js_function.dart,存放被原生调用的函数名称

将要提供给原生调用的函数,通过 js.context[原生调用名称] = 函数 开放给外部调用

如果在FlutterWeb工程要使用这个函数也可以使用@JS注解

WebView 创建时会回调 onWebViewCreated 获得 WebViewController ,WebViewController 调用 runJavascript 会执行JS函数无返回值,调用 runJavascriptReturningResult 会执行JS函数有返回值。

FutureBuilder获取WebViewController, 需要使用的地方直接调用

使用 html,CSS,Canvas 和 SVG 元素来渲染。

缺点:会存在不同平台效果不一样。

优点:不加载canvaskit默认使用系统字体,加载过程没有多余开销。

需要用到wasm,WebAssembly 要求需要浏览器支持,WebView Android需要最低需要57,Safari iOS 需要最低需要 11。

缺点:canvaskit 有7m大默认地址在国外首次加载耗时;中文会加载字体库默认地址在国外加载慢。

优点:性能更好,渲染效果一致。

--web-renderer=auto 默认移动端浏览器选择 HTML,桌面端浏览器选择 CanvasKit。

--web-renderer=html 使用 HTML 渲染器

--web-renderer=canvaskit 使用 CanvasKit 渲染器

综上所诉推荐移动端使用HTML渲染更合适,在编译和打包时指定渲染器 --web-renderer=html 。

--debug 模式构建的 Web 应用没有被压缩,且 Tree-shaking 没有执行。

--profile 模式构建的 Web 应用没有被压缩,但 Tree-shaking 执行了。

--release 模式构建的 Web 应用被压缩了,并且 Tree-shaking 执行了

运行命令

flutter run web --dart-define=FLUTTER_WEB_CANVASKIT_URL=./canvaskit/ --web-renderer=html

flutter run web --dart-define=FLUTTER_WEB_CANVASKIT_URL=./canvaskit/ --web-renderer=html --profile

打包命令

flutter build web --dart-define=FLUTTER_WEB_CANVASKIT_URL=./canvaskit/ --web-renderer=html --release

Android WebView与H5交互汇总

目前APP中内嵌Web页面非常常见,为了Web网页可以和原生进行交互,需要设计一套js-bridge,而这个桥接的设计底层都还是依赖系统提供的Webview与H5的交互,现有交互方式汇总如下:

1、原生调用JS

原生调用JS即在原生代码中调用执行当前网页中js代码,现有两种方法

1)WebView#loadUrl("javascript:func('" + arg + "')")

2) WebView#evaluateJavascript(String script, @Nullable ValueCallback<String> resultCallback)

其中第二种方法,从android4.4版本才支持,两种方法比较起来,也是第二种方法优于第一种方法:

1)第二种方法执行效率比第一种方法高 

2)第一种方法会触发页面刷新,第二种方法不会触发页面刷新

3)第二种方法可以直接获取js函数执行的返回值,而第一种想要获取返回值比较麻烦,需要设计一套机制,通过JS调用原生的方式把返回值传递过来

2、H5调用原生

即H5主动调用原生代码,可以执行原生函数或者获取原生返回的数据,通常有3中方法:

1)WebView#addJavascriptInterface(Object object, String name) 进行对象映射
2)WebViewClient#shouldOverrideUrlLoading() 来拦截Url调用代码
3)WebChromeClient 的 onJsAlert()、onJsConfirm()、
onJsPrompt() 拦截 js 中的对话框 alert() / confirm() / prompt()

实际上第一种方法是官方提供的H5调用原生的方法,后面两种是利用官方API规则自己模拟实现了H5调用原生的方法。

第一种方法类似于注入一个JS对象到H5页面中,而这个JS对象映射到了一个JAVA对象,在H5中直接调用这个JS对象的方法就可以调用到AVA对象,它的效率也是比较高的。但是因为这个设计在4.2以前的版本有安全漏洞,所以之前很多人放弃了这种调用方式。漏洞在4.2的版本解决了,简单讲就是供JS调用的方法添加注解@JavascriptInterface即可。

第二种第三种本质是一样的,拿第二种举例,在H5端发起页面跳转时,首先会被原生的shouldOverrideUrlLoading()函数拦截并决定是否进行跳转,那么我们可以约定一个特定格式的URL,当拦截到跳转发现是这种格式的URL,我们可以认为这是一个H5发起的桥接调用,我们解析执行原生代码,不进行跳转。例如拦截到的URL格式为:myapp://getuser?param=xxxxx,我们可以认为myapp开头的就是我们约定的桥接函数,后面的getuser是函数名,需要的入参和返回值回调函数通过param的值获取。这种拦截的方式实现,把原生的值返回给H5比较麻烦,通常的实现思路是在H5中给回调函数制定一个编号,原生通过上面原生调用H5的方法调用H5的处理函数,把回调函数编号和结果传递过去,再由H5的处理函数执行回调函数。

以上是关于FlutterWeb 和 WebView 原生交互调用的主要内容,如果未能解决你的问题,请参考以下文章

Android原生webview中js交互

iOS的webview和JavaScript的交互方法,求个小Demo,

Android WebView与H5交互汇总

Android WebView与H5交互汇总

Android WebView与H5交互汇总

安卓原生与hml交互(WebView基础)