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();



完结