vlambda博客
学习文章列表

Flutter加载Html并实现与JS 的双向调用

题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。

——  风雨来临,吾辈当乘风破浪。



本篇文章讲述的内容可以用来加载 Html 页面,以实现 Android 中 WebView 或者 是 iOS 中的 UIWebView 中的功能。

小编已将些插件提交github与pub仓库,读者可以直接添加引用依赖来使用。


Flutter_Fai_Webview 插件可实现的功能:

  1. 同时适配于 Android Ios 两个平台

  2. 通过 url 来加载渲染一个Html 页面

  3. 加载 Html 文本数据 如 <html> .... </html>等

  4. 加载 Html 标签数据 如 <p> ... </p>

  5. 实现 WebView 加载完成后,自动测量 WebView 的高度,并回调 Flutter

  6. 实现 WebView 加载完成监听

  7. 实现 WebView 上下滑动、滑动到顶部兼听、滑动到底部兼听并回调 Flutter

  8. 实现 兼听 WebView 输出日志并将日志回调 Flutter

  9. 实现 为 Html 页面中所有的图片添加点击事件 并回调 Flutter

  10. 实现Html与Flutter的JS双向互调

  11. 实现打开相机相册的功能

  12. 实现回退历史浏览记录的功能

  13. 实现监听Html中图片的点击事件回调

  14. 刷新Html页面的加载


Flutter中可用于来加载 Html 页面的插件 ,

  1. flutter_WebView_plugin

  2. webView_flutter

  3. flutter_inappbrowser

  4. html

  5. flutter_html

  6. flutter_html_view


这些多多少满足不了我项目中的需求,所以花了几天时间开发了 Flutter_Fai_Webview 插件,可实现 Android 中 WebView 或者 是 iOS 中的 UIWebView 中的功能,因为 Flutter_Fai_Webview 插件本质上是通过 PlatformView 功能将原生的 View 嵌套在 Flutter 中。

插件源码在这里

https://github.com/zhaolongs/Flutter_Fai_Webview



开发插件要具备的知识:



  • Flutter 与 原生 Android iOS 双向通信

  • Flutter通过MethodChannel实现Flutter 与Android iOS 的双向通信

  • Flutter通过BasicMessageChannel实现Flutter 与Android iOS 的双向通信

  • Flutter 中内嵌 Android iOS 原生View的编程基础

  • flutter调用android 原生TextView

  • flutter调用ios 原生View

  • 最重要的一点是 具备 Android iOS 原生语言的开发能力


可点击文章末尾的查看原文链接来查看这里的系列分析文章。



开始使用

1 基本使用说明

1.1 Flutter 项目中 pubspec.xml 文件中 配置插件

pub方式依赖:点击这里查看最新版本

https://pub.flutter-io.cn/packages/flutter_fai_webview


dependencies: flutter_fai_webview: ^1.0.0



git方式依赖:

  flutter_fai_webview:    git:      url: https://github.com/zhaolongs/Flutter_Fai_Webview.git      ref: master

1.2 在使用到 WebView 页面中

引入头文件


import 'package:flutter_fai_webview/flutter_fai_webview.dart';


1.3 通过url加载网页

String htmlUrl = "https://blog.csdn.net/zl18603543572";

然后使用FaiWebViewWidget来加载显示这个h5链接,代码如下:

  ///通过url加载页面 FaiWebViewWidget buildFaiWebViewWidget() { return FaiWebViewWidget( //webview 加载网页链接 url: htmlUrl, //webview 加载信息回调 callback: callBack, //输出日志 isLog: true, ); }

其中callBack是一个回调,如webview的加载完成、向上滑动、向下滑动等等,代码如下:

  

 ///加载 Html 的回调 ///[code]消息类型标识 ///[msg] 消息内容 ///[content] 回传的参数 void callBack(int code, String msg, content) { //加载页面完成后 对页面重新测量的回调 //这里没有使用到 //当FaiWebViewWidget 被嵌套在可滑动的 widget 中,必须设置 FaiWebViewWidget 的高度 //设置 FaiWebViewWidget 的高度 可通过在 FaiWebViewWidget 嵌套一层 Container 或者 SizeBox if (code == 201) { //页面加载完成后 测量的 WebView 高度 double webViewHeight = content; print("webViewHeight " + webViewHeight.toString()); } else { //其他回调 } setState(() { message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]"; }); }

运行效果如下图所示:

完整代码在这里

https://github.com/zhaolongs/Flutter_Fai_Webview/blob/master/example/lib/exampl_default_url_max.dart


1.4 关于回调中的code取值说明如下

      •      201 测量webview 成功

      •      202 JS调用

      •      203 图片点击回调

      •      301 滑动到顶部

      •      302 向下滑动

      •      303 向上滑动

      •      304 滑动到底部

      •      401 webview 开始加载

      •      402 webview 加载完成

      •      403 webview html中日志输出

      •      404 webview 加载出错

      •      501 webview 弹框回调

      •      1000 操作失败


2 Flutter 加载页面

2.1 通过 url 加载 Html 页面

在上述1.3 通过url加载网页已进行过描述

2.2 通过 Html Data 加载 String类型的Html 页面

加载String类型的Html页面,一般先是将String类型的Html代码加载到内容中,如通过网络请求接口获取的,或者是在页面中定义好的代码如下:

 

 String htmlBlockData = "<!DOCTYPE html><html> <head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"> <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1\"> </head> <body><p>加载中</p></body></html>";

或者是放在assets目录的静态Html,那么就需要先读取静态资源目录下的Html文件 ,代码如下:

 ///读取静态Html Future<String> loadingLocalAsset() async { ///加载 String htmlData = await rootBundle.loadString('assets/html/test.html'); print("加载数据完成 $htmlData"); return htmlData; }

当然你需要配制好目录依赖,如我这里的example中的html文件配置代码如下:

 assets:    - assets/html/


对应的文件目录如下所示:


然后就是使用FaiWebViewWidget来渲染Html页面了,如果是直接显示已加载好的String类型的Html,那么直接配置FaiWebViewWidget中的htmlBlockData就可以,如果是使用异步加载assets目录下的静态Html,那么可以结合FutureBuilder组件来实现加载,代码如下:

 ///异步加载静态资源目录下的Html FutureBuilder<String> buildFutureBuilder() { return FutureBuilder<String>( ///异步加载数据 future: loadingLocalAsset(), ///构建 builder: (BuildContext context, var snap) { ///加载完成的html数据 String htmlData = snap.data; //使用插件 FaiWebViewWidget if (htmlData == null) { return CircularProgressIndicator(); } ///通过配置 htmlBlockData 来渲染 return FaiWebViewWidget( //webview 加载本地html数据 htmlBlockData: htmlData, //webview 加载信息回调 callback: callBack, //输出日志 isLog: true, ); }, ); }

对应的完整代码请在文章末尾点击查看原文

2 Flutter与Html中JS的双向互调

在这里使用到的Html页面代码如下:

<!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"></head><body><p><br/></p><p>测试一下 &nbsp;</p><p><img src="https://images.gitee.com/uploads/images/2020/0602/203000_9fa3ddaa_568055.png" title="" alt=""/></p><p><img src="https://images.gitee.com/uploads/images/2020/0602/203000_9fa3ddaa_568055.png" title="" alt=""/></p><p id="flutter"><br/></p>
<button type="button" onclick="toFlutter()">调用 Flutter中的内容</button><p><br/></p><p><br/></p>
<script>
///Flutter中回调JS的方法 function testAlert() { console.log(' 这里是JS 的方法 '); }
//Flutter调用的 JS方法 //这里传回的参数是 JSON 格式 //获取具体的参数内容 可以将 JSON文本转 对象或者是数组 function testAlert2(value) {
console.log(' 这里是JS 的方法 传的参数是 ' + value); ///交Json文本转对象 var obj = JSON.parse(value); console.log(' 解析字符串的数据 ' + obj.test); ///在HTML中p标签中输入传过来的cdvo document.getElementById('flutter').innerHTML = obj.test; }

//JS调用Flutter中的方法 function toFlutter() {
///向Flutter传递的参数 var obj = Object(); obj.name = '张三'; obj.age = 10; var json = JSON.stringify(obj);
///根据不同的手机加载不同的方法 var sys = checkSystem(); if (sys === 'ios') { controll.otherJsMethodCall(json); } else { otherJsMethodCall(json); } }
//判断是安卓还是IOS function checkSystem() { var u = window.navigator.userAgent, app = window.navigator.appVersion; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //g var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 if (isAndroid) { return 'android'; } if (isIOS) { return 'ios'; } }</script>
</body></html>


2.1 Flutter中调用JS中的方法

Flutter中调用JS方法,需要使用到FaiWebViewController,代码如下:

 ///webView控制器 FaiWebViewController faiWebViewController = new FaiWebViewController(); ///构建webview组件 FaiWebViewWidget buildFaiWebViewWidget(String htmlData) { return FaiWebViewWidget( controller: faiWebViewController, //webview 加载本地html数据 htmlBlockData: htmlData, //webview 加载信息回调 callback: callBack, //输出日志 isLog: true, ); }

然后在点击按钮的时候调用HTML中JS的方法,代码如下:

RaisedButton( child: Text("Flutter调用JS方法"), onPressed: () { ///向JS方法中传的参数 Map<String, dynamic> map = new Map(); map["test"] = "这是Flutter中传的参数";
///参数一为调用JS的方法名称 ///参数二为向JS中传递的参数 faiWebViewController.toJsFunction( jsMethodName: "testAlert2", parameterMap: map); }, )

这里使用到的testAlert2就是JS中声明的方法

2.2 JS中调用Flutter的方法

在上述描述到的Html文件中,声明了一个按钮,然后在点击按钮时调用 toFlutter方法,然后在Flutter中对应的FaiWebViewWidget设置的callback监听中会收到这个回调,处理代码如下:

 ///FaiWebViewWidget 的回调处理 callBack(int code, String msg, content) {  if (code == 202) { /// json.encode(mapData); //Map转化JSON字符串 /// json.decode(strData); //JSON 字符串转化为Map类型 Map<String, dynamic> map = json.decode(content);
String name = map["name"]; int age = map["age"]; print('这里是Js调用到Flutter中的数据 name $name age $age'); } else { //其他回调 } setState(() { message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]"; }); }

然后在这里接收到JS中的调用以及参数后,就可以在Flutter中做任何想要的操作

在正个过程中参数数据是通过json格式的数据来传递的,在实际项目开发中需要保持json的一至


4 Flutter操作Html的其他方法简述

4.1 刷新页面加载

通过 FaiWebViewController的 refresh方法就可实现,代码如下:

 

faiWebViewController.refresh();



完结