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


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>测试一下 &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方法//这里传回的参数是 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 的双向调用相关推荐

  1. flutter嵌入HTML5页面,Flutter加载Html并实现与JS 的双向调用

    2019-07-20 16:01:01 早起的年轻人 阅读数 2025 收藏更多 可以用来加载 Html 页面,以实现 Android 中 WebView 或者 是 iOS 中的 UIWebView ...

  2. 【解决方案】如何实现在HTML页面加载完毕后运行某个js

    前景: 今天在开发过程中,发现我js文件里面的方法没有响应,后来发现是js在html中引入的位置不对.我在head中加载了js,导致我js中的document.getElementById方法失效.因 ...

  3. cdn加载vue很慢_Vue.js 项目打包优化实践

    首先上结果: 把常用的 Vue,router,vuex,axios 的 runtime 包拆分了出来,改为 cdn: 另外就是对于自己编写的业务代码进行分包,根据路由进行懒加载,可以较好的提高首屏加载 ...

  4. js控制css 加载,CSS样式表的加载对于DOM解析,渲染,JS执行的阻塞问题

    CSS加载问题 css加载会不会阻塞DOM树的解析? css加载会不会阻塞DOM树的渲染? css加载会不会阻塞后面js语句的执行? css阻塞 h1 { color: red !important ...

  5. Flutter 加载图片方法

    写文章的目的是记录一下学习Flutter过程,二是解惑一下网上流传的Flutter 加载图片其实好多是有坑的,即无法加载图片.画重点了:目前Flutter 加载2倍图,3倍图是没有好的方案的.要想加载 ...

  6. flutter 页面加载动画_十、Flutter加载动画

    目录 一.效果展示 二.RoundPainter 三.RoundProgress 四.旋转起来 五.停止旋转 一.效果展示 Flutter加载动画.jpg 二.RoundPainter 同上篇文章&l ...

  7. Flutter:加载本地Html、WebView与JS交互

    本次教程使用的是Flutter官方提供的WebView组件webview_flutter 2.3.1,flutter_android 2.2.1 一. WebView介绍 以下为Flutter Web ...

  8. Flutter与JS的双向调用、Flutter中Widget与Html混合加载

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...

  9. Flutter 加载3D模型方案总结

    文章目录 前言 一.flutter_cube 1.依赖 2.使用 二.model_viewer_plus 1.依赖 2.配置 2.使用 三.结合three.js 1. 配置three.js 下载资源 ...

最新文章

  1. Linux拜拜!微软给WSL加入GPU支持,Windows终于迎来命令行包管理工具
  2. java处理日期时间 相加减
  3. c语言的语言扩展的数据类型,C语言之数据类型
  4. IT团队之非正式沟通
  5. [转]C#多线程编程实例实战
  6. flink常见算子的一些操作
  7. led计数电路实验报告_至简设计系列_状态机实现LED交通灯2
  8. 从零开始实现ASP.NET Core MVC的插件式开发(一) - 使用ApplicationPart动态加载控制器和视图
  9. 017-Centos7.6+CDH 6.2 安装和使用
  10. cycleGAN有matlab代码吗,CycleGAN的代码组成
  11. Codeforces Round #438 B. Race Against Time
  12. 如何从网站提取数据?
  13. 带声调的拼音转拼音+数字
  14. 数据结构 -- 栈的基本操作(入栈、出栈、取栈顶元素)
  15. 用C#实现鼠标左右键的切换
  16. 分布式系统之----CAP理论
  17. 深入浅出—Redux-saga源码
  18. 计算机屏幕面积大约多少,电脑屏幕尺寸怎么计算?-常见电脑屏幕尺寸的计算方式 - 河东软件园...
  19. Labview Actorfromwork ESA(发布订阅模式,即观察者模式)Demo,整体操作过程已录制视频
  20. hgame2023 WebMisc

热门文章

  1. ​全网首发,TensorFlow 2.0 中文视频教程来啦
  2. 美人秀色空绝世,我用PS-GAN试伊妆
  3. HTML表格属性跨列,HTML表格的使用 与 跨行跨列
  4. java监听双按键_java 键盘监听 按一次键监听到两次
  5. 700 页的机器学习笔记火啦,图文生动形象
  6. 李飞飞点赞!,刚刚公布了第一批数据集benchmark入围名单
  7. 揭秘自动驾驶纯视觉算法,探索自动驾驶的未来
  8. 复练-关于面试的科技树-能力三核的彩蛋
  9. 将已有项目转为se项目_威海将再添国家级非遗项目
  10. spring的事务隔离_spring事务基础及常见问题详解