Flutter网页视图展示插件flutter_fai_webview的使用
Flutter网页视图展示插件flutter_fai_webview的使用
Flutter 加载 Html Flutter与JS的双向调用
Flutter是谷歌推出的最新的移动开发框架。
1. 基本使用说明
1.1 Flutter 项目中 pubspec.yaml
文件中 配置插件
dependencies:
flutter_fai_webview: ^1.0.0
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() + "]";
});
}
运行效果如下图所示:
完整代码在这里:
import 'package:flutter/material.dart';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String htmlUrl = "https://blog.csdn.net/zl18603543572";
double webViewHeight = 1;
void callBack(int ?code, String ?msg, content) {
// 加载页面完成后 对页面重新测量的回调
if (code == 201) {
// 更新高度
webViewHeight = content;
print("webViewHeight " + content.toString());
} else {
// 其他回调
}
setState(() {
message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("FaiWebViewWidget 加载 html"),
),
body: buildFaiWebViewWidget(),
),
);
}
FaiWebViewWidget buildFaiWebViewWidget() {
return FaiWebViewWidget(
url: htmlUrl,
callback: callBack,
isLog: true,
);
}
}
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,详细说明如下:
// 当前点击的图片 URL
String 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) {
// 加载页面完成后 对页面重新测量的回调
webViewHeight = content;
} else if (code == 202) {
// Html 页面中 Js 的回调
String jsJson = content;
} else if (code == 203) {
// 为 Html 页面中的图片添加 点击事件后,点击图片会回调此方法
String jsJson = content;
} 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 == 404) {
// 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文件,代码如下:
///读取静态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,
);
},
);
}
完整的代码在这里:
import 'package:flutter/material.dart';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("FaiWebViewWidget 加载 html"),
),
body: buildFutureBuilder(),
),
);
}
Future<String> loadingLocalAsset() async {
String htmlData = await rootBundle.loadString('assets/html/test.html');
print("加载数据完成 $htmlData");
return htmlData;
}
FutureBuilder<String> buildFutureBuilder() {
return FutureBuilder<String>(
future: loadingLocalAsset(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return FaiWebViewWidget(
htmlBlockData: snapshot.data!,
callback: callBack,
isLog: true,
);
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return Text("加载失败");
}
},
);
}
void callBack(int ?code, String ?msg, content) {
if (code == 201) {
// 加载页面完成后 对页面重新测量的回调
webViewHeight = content;
print("webViewHeight " + content.toString());
} else {
// 其他回调
}
setState(() {
message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
});
}
}
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 {
@override
MaxUrlHexRefreshState createState() => MaxUrlHexRefreshState();
}
class MaxUrlHexRefreshState extends State<DefaultHexRefreshPage> {
String message = "--";
String htmlUrl = "https://blog.csdn.net/zl18603543572";
double webViewHeight = 1;
@override
void initState() {
super.initState();
}
@override
Widget 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(),
);
}
Widget buildRefreshHexWidget() {
return RefreshIndicator(
onRefresh: _onRefresh,
child: SingleChildScrollView(
child: Column(
children: [
Container(
color: Colors.grey,
height: 220.0,
child: Column(mainAxisSize: MainAxisSize.min, children: [
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(
url: htmlUrl,
callback: callBack,
isLog: true,
),
),
],
),
),
);
}
Future<void> _onRefresh() async {
return await Future.delayed(Duration(seconds: 1), () {
print('refresh');
webViewWidget.refresh();
});
}
void 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的双向互调
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 的回调处理
void 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中做任何想要的操作。
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网页视图展示插件flutter_fai_webview的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网页视图展示插件flutter_fai_webview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用flutter_fai_webview
插件来展示网页视图的代码示例。请注意,flutter_fai_webview
可能不是一个广泛认知的插件,我假设你提到的插件类似于webview_flutter
,因为webview_flutter
是Flutter官方推荐使用的Web视图插件。如果flutter_fai_webview
有特定的API差异,请参考其官方文档进行调整。以下示例基于webview_flutter
,你可以根据flutter_fai_webview
的文档进行相应修改。
首先,确保你已经在pubspec.yaml
文件中添加了依赖项(这里以webview_flutter
为例,请替换为flutter_fai_webview
的实际依赖项):
dependencies:
flutter:
sdk: flutter
webview_flutter: ^3.0.4 # 请替换为flutter_fai_webview的实际版本
然后,运行flutter pub get
来安装依赖。
接下来,在你的Flutter项目中创建一个新的Dart文件(例如webview_page.dart
),并在其中实现WebView的展示:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart'; // 请替换为flutter_fai_webview的实际import路径
class WebViewPage extends StatefulWidget {
final String url;
WebViewPage({required this.url});
@override
_WebViewPageState createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
late WebViewController _controller;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView Demo'),
),
body: WebView(
initialUrl: widget.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
onPageFinished: (String url) {
print("Page finished loading: $url");
},
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith("https://your-domain.com/")) {
return NavigationDecision.navigate;
} else if (request.isForMainFrame) {
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
);
}
// 示例:加载新的URL
void _loadUrl(String url) async {
if (await _controller.canGoBack()) {
_controller.goBack();
} else {
_controller.loadUrl(url);
}
}
}
在你的主应用程序文件(例如main.dart
)中,导航到这个新创建的WebView页面:
import 'package:flutter/material.dart';
import 'webview_page.dart'; // 导入你创建的WebView页面
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter WebView Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter WebView Demo Home'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => WebViewPage(url: 'https://www.example.com')),
);
},
child: Text('Open WebView'),
),
),
);
}
}
这个示例展示了如何在Flutter应用中集成并使用WebView来显示一个网页。如果你使用的是flutter_fai_webview
,请参考其官方文档来调整import
路径和API调用。通常,WebView插件的使用模式大同小异,主要区别在于具体的API细节。