Flutter加载Html并实现与JS 的双向调用
题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精。
Flutter是谷歌推出的最新的移动开发框架。
【x1】微信公众号的每日提醒 随时随记 每日积累 随心而过
【x2】各种系列的视频教程 免费开源 关注 你不会迷路
【x3】系列文章 百万 Demo 随时 复制粘贴 使用
大家如果有问题可以随时关注公众号联系作者,沟通解决需求。
- 2020-11-20 更新 1.1.6 版本
- 新增 WebView 添加 脚视图的功能
- 新增自定义webView高度的功能
- 2020-10-30 更新 1.1.5版本
- 添加 加载中显示文案
- 兼容部分机型有底部虚拟菜单栏无法监听回调问题
- 优化 ScrollView 与 WebView 的兼容显示
2020-10-28 更新1.1.4 版本 处理 Flutter与Html的混合页面加载
2020-10-27 更新 1.1.3 版本 优化处理在 Android平台加载显示短暂的黑屏问题
2020-7-26 更新支持 Android iOS 平台向前或者是后退浏览历史功能
请查看本文章第四小节2020-8-12 修复在iphone8早JS调用Flutter失效问题版本1.1.1
本篇文章讲述的内容可以用来加载 Html 页面,以实现 Android 中 WebView 或者 是 iOS 中的 UIWebView 中的功能。
Flutter_Fai_Webview 插件可实现的功能:
- 同时适配于 Android Ios 两个平台
- 通过 url 来加载渲染一个Html 页面
- 加载 Html 文本数据 如
<html> .... </html>
等 - 加载 Html 标签数据 如
<p> ... </p>
- 实现 WebView 加载完成后,自动测量 WebView 的高度,并回调 Flutter
- 实现 WebView 加载完成监听
- 实现 WebView 上下滑动、滑动到顶部兼听、滑动到底部兼听并回调 Flutter
- 实现 兼听 WebView 输出日志并将日志回调 Flutter
- 实现 为 Html 页面中所有的图片添加点击事件 并回调 Flutter
- 实现Html与Flutter的JS双向互调
- 实现打开相机相册的功能
- 实现回退历史浏览记录的功能
- 实现监听Html中图片的点击事件回调
- 刷新Html页面的加载
Flutter中可用于来加载 Html 页面的插件 ,
- flutter_WebView_plugin
- webView_flutter
- flutter_inappbrowser
- html
- flutter_html
- flutter_html_view
这些多多少满足不了我项目中的需求,所以花了几天时间开发了 Flutter_Fai_Webview 插件,可实现 Android 中 WebView 或者 是 iOS 中的 UIWebView 中的功能,因为 Flutter_Fai_Webview 插件本质上是通过 PlatformView 功能将原生的 View 嵌套在 Flutter 中。
插件源码在这里
开发插件要具备的知识:
- 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方式依赖:点击这里查看最新版本
dependencies:flutter_fai_webview: ^1.0.0
git方式依赖:
flutter_fai_webview:git:url: https://github.com/zhaolongs/Flutter_Fai_Webview.gitref: 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 或者 SizeBoxif (code == 201) {//页面加载完成后 测量的 WebView 高度double webViewHeight = content;print("webViewHeight " + webViewHeight.toString());} else {//其他回调}setState(() {message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";});}
运行效果如下图所示:
完整代码在这里
1.4 关于回调中的code取值说明如下
code值 | 简述 |
---|---|
201 | 测量webview 成功 |
202 | JS调用 |
203 | 图片点击回调 |
301 | 滑动到顶部 |
302 | 向下滑动 |
303 | 向上滑动 |
304 | 滑动到底部 |
401 | webview 开始加载 |
402 | webview 加载完成 |
403 | webview html中日志输出 |
404 | webview 加载出错 |
501 | webview 弹框回调 |
1000 | 操作失败 |
加载Html的过程中会实时回调Flutter,详细说明如下:
/*** code 原生 Android iOS 回调 Flutter 的消息类型标识* message 消息类型日志* content 回调的基本数据*/Function(int code, String message, dynamic content) callback;
详细说明
//当前点击的图片 URLString imageUrl = null;//是否显示浮动按钮bool isShowFloat = false;/*** code 当前点击图片的 位置* url 当前点击图片对应的 链接* images 当前 Html 页面中所有的图片集合*/void imageCallBack(int code, String url, List<String> images) {imageUrl = url;setState(() {});}void callBack(int code, String msg, content) {String call = "回调 code:" +code.toString() +" msg:" +msg.toString() +" content:" +content.toString();if (code == 201) {//加载页面完成后 对页面重新测量的回调//这里没有使用到//当FaiWebViewWidget 被嵌套在可滑动的 widget 中,必须设置 FaiWebViewWidget 的高度//设置 FaiWebViewWidget 的高度 可通过在 FaiWebViewWidget 嵌套一层 Container 或者 SizeBoxwebViewHeight = content;} else if (code == 202) {// Html 页面中 Js 的回调// Html 页面中的开发需要使用 Js 调用 【 Android 中 使用 controll.otherJsMethodCall( json )】 【iOS中 直接调用 otherJsMethodCall( json ) 】// 在 Flutter 中解析 json 然后加载不同的功能String jsJson = content;} else if (code == 203) {// 为 Html 页面中的图片添加 点击事件后,点击图片会回调此方法// content 为当前点击图片的 地址// 实现更多功能 比如 一个 Html 页面中 有5张图片,点击放大查看并可右右滑动// 这个功能可以在 imageCallBack 回调中处理} else if (code == 301) {//当 WebView 滑动到顶部的回调} else if (code == 302) {//当 WebView 开始向下滑动时的回调//隐藏按钮isShowFloat = true;} else if (code == 303) {//当 WebView 开始向上滑动时的回调//显示按钮isShowFloat = false;} else if (code == 304) {//当 WebView 滑动到底部的回调} else if (code == 401) {//当 WebView 开始加载的回调} else if (code == 402) {//当 WebView 加载完成的回调} else if (code == 403) {// WebView 中 Html中日志输出回调} else if (code == 401) {// WebView 加载 Html 页面出错的回调} else if (code == 501) {// 当 Html 页面中有 Alert 弹框弹出时 回调消息} else if (code == 1000) {// 操作失败 例如 空指针异常 等等} else {//其他回调}setState(() {message = call;});}
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文件 ,代码如下:
///读取静态HtmlFuture<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组件来实现加载,代码如下:
///异步加载静态资源目录下的HtmlFutureBuilder<String> buildFutureBuilder() {return FutureBuilder<String>(///异步加载数据future: loadingLocalAsset(),///构建builder: (BuildContext context, var snap) {///加载完成的html数据String htmlData = snap.data;//使用插件 FaiWebViewWidgetif (htmlData == null) {return CircularProgressIndicator();}///通过配置 htmlBlockData 来渲染return FaiWebViewWidget(//webview 加载本地html数据htmlBlockData: htmlData,//webview 加载信息回调callback: callBack,//输出日志isLog: true,);},);}
对应的完整代码在这里
2.3 加载混合页面
也就是说 一个页面中,一部分是 Flutter Widget 一部分是 webview 加载。
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';/*** 混合页面加载**/
class DefaultHexRefreshPage extends StatefulWidget {@overrideMaxUrlHexRefreshState createState() => MaxUrlHexRefreshState();
}class MaxUrlHexRefreshState extends State<DefaultHexRefreshPage> {//原生 发送给 Flutter 的消息String message = "--";String htmlUrl = "https://blog.csdn.net/zl18603543572";double webViewHeight = 1;@overridevoid initState() {super.initState();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(leading: IconButton(onPressed: () {Navigator.pop(context);},icon: Icon(Icons.arrow_back_ios),),title: Container(padding: EdgeInsets.only(left: 10, right: 10),height: 28,alignment: Alignment(0, 0),color: Color.fromARGB(90, 0, 0, 0),child: Text(message,style: TextStyle(color: Colors.white, fontSize: 12),),),),body: buildRefreshHexWidget(),);}/*** 需要注意的是 * RefreshIndicator 会覆盖 WebView 的滑动事件* 所有关于 监听 WebView 的滑动监听将会失效*/Widget buildRefreshHexWidget() {return RefreshIndicator(//下拉刷新触发方法onRefresh: _onRefresh,//设置webViewWidgetchild: SingleChildScrollView(child: Column(children: <Widget>[Container(color: Colors.grey,height: 220.0,child: Column(mainAxisSize: MainAxisSize.min,children: <Widget>[Center(child: Text("这里是 Flutter widget "),)],),),Align(alignment: Alignment(0, 0),child: Text("以下是 Html 页面 "),),Container(color: Colors.redAccent,height: 1.0,),Container(height: webViewHeight,child: FaiWebViewWidget(//webview 加载网页链接url: htmlUrl,//webview 加载信息回调callback: callBack,//输出日志isLog: true,),)],),),);}Future<Null> _onRefresh() async {return await Future.delayed(Duration(seconds: 1), () {print('refresh');webViewWidget.refresh();});}callBack(int code, String msg, content) {//加载页面完成后 对页面重新测量的回调if (code == 201) {//更新高度webViewHeight = content;print("webViewHeight " + content.toString());} else {//其他回调}setState(() {message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";});}
}
3 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>测试一下 </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方法//这里传回的参数是 JSON 格式//获取具体的参数内容 可以将 JSON文本转 对象或者是数组function testAlert2(value) {console.log(' 这里是JS 的方法 传的参数是 ' + value);///交Json文本转对象var obj = JSON.parse(value);console.log(' 解析字符串的数据 ' + obj.test);///在HTML中p标签中输入传过来的cdvodocument.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 === 'android') {controll.otherJsMethodCall(json);} else {otherJsMethodCall(json);}}//判断是安卓还是IOSfunction checkSystem() {var u = window.navigator.userAgent, app = window.navigator.appVersion;var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //gvar isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端if (isAndroid) {return 'android';}if (isIOS) {return 'ios';}}</script></body>
</html>
3.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中声明的方法
3.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();
4.2 浏览器的后退
///判断是否可退 如果可退bool back = await _faiWebViewController.canBack();print("是否可后退 $back");if (back) {/// 如果可退 后退浏览器的历史_faiWebViewController.back();} else {///如果不可就退出当前页面Navigator.of(context).pop();}
4.3 浏览器的前进
///判断是否可前进bool forword = await _faiWebViewController.canForword();print("是否可前进$forword");if (forword) {/// 如果可退 后退浏览器的历史_faiWebViewController.forword();} else {}
完结
Flutter加载Html并实现与JS 的双向调用相关推荐
- flutter嵌入HTML5页面,Flutter加载Html并实现与JS 的双向调用
2019-07-20 16:01:01 早起的年轻人 阅读数 2025 收藏更多 可以用来加载 Html 页面,以实现 Android 中 WebView 或者 是 iOS 中的 UIWebView ...
- 【解决方案】如何实现在HTML页面加载完毕后运行某个js
前景: 今天在开发过程中,发现我js文件里面的方法没有响应,后来发现是js在html中引入的位置不对.我在head中加载了js,导致我js中的document.getElementById方法失效.因 ...
- cdn加载vue很慢_Vue.js 项目打包优化实践
首先上结果: 把常用的 Vue,router,vuex,axios 的 runtime 包拆分了出来,改为 cdn: 另外就是对于自己编写的业务代码进行分包,根据路由进行懒加载,可以较好的提高首屏加载 ...
- js控制css 加载,CSS样式表的加载对于DOM解析,渲染,JS执行的阻塞问题
CSS加载问题 css加载会不会阻塞DOM树的解析? css加载会不会阻塞DOM树的渲染? css加载会不会阻塞后面js语句的执行? css阻塞 h1 { color: red !important ...
- Flutter 加载图片方法
写文章的目的是记录一下学习Flutter过程,二是解惑一下网上流传的Flutter 加载图片其实好多是有坑的,即无法加载图片.画重点了:目前Flutter 加载2倍图,3倍图是没有好的方案的.要想加载 ...
- flutter 页面加载动画_十、Flutter加载动画
目录 一.效果展示 二.RoundPainter 三.RoundProgress 四.旋转起来 五.停止旋转 一.效果展示 Flutter加载动画.jpg 二.RoundPainter 同上篇文章&l ...
- Flutter:加载本地Html、WebView与JS交互
本次教程使用的是Flutter官方提供的WebView组件webview_flutter 2.3.1,flutter_android 2.2.1 一. WebView介绍 以下为Flutter Web ...
- Flutter与JS的双向调用、Flutter中Widget与Html混合加载
题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...
- Flutter 加载3D模型方案总结
文章目录 前言 一.flutter_cube 1.依赖 2.使用 二.model_viewer_plus 1.依赖 2.配置 2.使用 三.结合three.js 1. 配置three.js 下载资源 ...
最新文章
- Linux拜拜!微软给WSL加入GPU支持,Windows终于迎来命令行包管理工具
- java处理日期时间 相加减
- c语言的语言扩展的数据类型,C语言之数据类型
- IT团队之非正式沟通
- [转]C#多线程编程实例实战
- flink常见算子的一些操作
- led计数电路实验报告_至简设计系列_状态机实现LED交通灯2
- 从零开始实现ASP.NET Core MVC的插件式开发(一) - 使用ApplicationPart动态加载控制器和视图
- 017-Centos7.6+CDH 6.2 安装和使用
- cycleGAN有matlab代码吗,CycleGAN的代码组成
- Codeforces Round #438 B. Race Against Time
- 如何从网站提取数据?
- 带声调的拼音转拼音+数字
- 数据结构 -- 栈的基本操作(入栈、出栈、取栈顶元素)
- 用C#实现鼠标左右键的切换
- 分布式系统之----CAP理论
- 深入浅出—Redux-saga源码
- 计算机屏幕面积大约多少,电脑屏幕尺寸怎么计算?-常见电脑屏幕尺寸的计算方式 - 河东软件园...
- Labview Actorfromwork ESA(发布订阅模式,即观察者模式)Demo,整体操作过程已录制视频
- hgame2023 WebMisc
热门文章
- ​全网首发,TensorFlow 2.0 中文视频教程来啦
- 美人秀色空绝世,我用PS-GAN试伊妆
- HTML表格属性跨列,HTML表格的使用 与 跨行跨列
- java监听双按键_java 键盘监听 按一次键监听到两次
- 700 页的机器学习笔记火啦,图文生动形象
- 李飞飞点赞!,刚刚公布了第一批数据集benchmark入围名单
- 揭秘自动驾驶纯视觉算法,探索自动驾驶的未来
- 复练-关于面试的科技树-能力三核的彩蛋
- 将已有项目转为se项目_威海将再添国家级非遗项目
- spring的事务隔离_spring事务基础及常见问题详解