flutter层不支持webview,加载网页的功能还需要借助控件来处理。
通过pub.dev搜索以及对比网上文章,发现了几个比较受欢迎的flutter webview插件;
这三种插件对比图(此图借鉴自网络)
这里详细介绍使用flutter_inappwebview5.3.2版本插件完成交互;
注意:flutter_inappwebview6.xx 版本flutter3.0以下不支持;
控件地址:https://pub.dev/packages/flutter_inappwebview。
1.安装插件
1)在配置文件pubbspec.yaml中加 flutter_inappwebview: 5.3.2;然后运行flutter pub get同步插件;
flutter_inappwebview: 5.3.2
2.配置
1)在入口文件main.dart中加入
// 不加这个强制横/竖屏会报错
WidgetsFlutterBinding.ensureInitialized();
3.主要类概览
该插件主要提供了以下类:
- InAppWebView :一个 Flutter 小部件,用于添加整合到 Flutter 部件树的内联原生 WebView。
- ContextMenu :该类表示 WebView 的快捷菜单。
- HeadlessInAppWebView :该类表示处于 headless 模式的 WebView。它可以用来在后台运行 WebView,而无需将 InAppWebView 附加到部件树中。
- InAppBrowser :使用原生 WebView 的 In-App Browser。
- ChromeSafariBrowser :使用 Chrome Custom Tabs (Android)和 SFSafariViewController (iOS)的 In-App Browser。
- InAppLocalhostServer :该类让你可以创建一个简单的服务器: http://localhost:[port]/ . ,默认 port 为 8080 。
- CookieManager :这个类实现了一个单例对象(共享实例),管理 WebView 实例使用的 cookie。
- HttpAuthCredentialDatabase :该类实现一个管理共享 HTTP 身份验证凭据缓存的单例对象(共享实例)。
- WebStorageManager :该类生成一个管理 Web 存储(供 WebView 实例使用)的单例对象(共享实例)。
- ......
4.使用
(1)加载webview视图
1)展示一个url的视图内容
flutter代码如下:
app上呈现的效果图:
2) 展示一个html视图内容
html代码如下:
flutter代码:
在app上呈现的效果:
3)在flutter代码中处理你url文件或html文件的某个demo结构
以html文件为例,我想要在箭头所指的demo结构处添加文字内容“12345678910”和一些样式
那么在flutter代码中添加
//在InAppWebView配置项中添加
onPageCommitVisible: (inAppWebViewControlle, uri) async {
//_loadPage是声明的一个全局bool类型变量
if (_loadPage) {
setState(() {
_loadPage = false;
});
//获取到webview的所有html结构
var fileHtmlContents = await webViewController!.getHtml();
//找到带有某种唯一标识的demo结构并替换它
fileHtmlContents = fileHtmlContents!.replaceAll(
'<div class="flutter-view"></div>',
"<div class='flutter-view' style='width: 200px; height: 200px;background-color: green;'>12345678910</div>",
);
//重新渲染结构
webViewController!.loadData(data: fileHtmlContents);
}
},
效果:
(2)与js交互传参
在flutter代码中添加
//添加在InAppWebView配置项里
// InAppWebview中获取InAppWebViewController
onWebViewCreated: (InAppWebViewController controller) {
// 注册一个JS处理方法,名称为myHandlerName
controller.addJavaScriptHandler(
handlerName: 'myHandlerName',
callback: (args) {
// 打印js方传递过来的参数
print('args=js方传递过来的参数============================$args');
// 传给js方的参数
// 可以传递你所需要的任意类型数据,数组、对象等
return "flutter给js的数据";
});
},
//这个方法可以打印js中的conse.log内容
onConsoleMessage: (controller, consoleMessage) {
//这里是打印来自于js的conse.log打印
print("consoleMessage==来自于js的打印====$consoleMessage");
},
在js代码中添加
// 下面的"flutterInAppWebViewPlatformReady"为固定写法
// "myHandlerName"与flutter中注册的JS处理方法名称一致
window.addEventListener("flutterInAppWebViewPlatformReady", function () {
window.flutter_inappwebview
//可以传递你所需要的任意类型数据,数组、对象等
.callHandler("myHandlerName", "这里是传给flutter的参数")
.then(function (res) {
console.log("res========flutter给html的数据", res);
})
})
flutter控制台输出:
传递数据成功啦,可以开始你对这些数据的处理啦。
注意:每次修改了html文件代码都需要终止flutter项目进程重新启动,否则你将看不到你的改动效果。
(3)完整demo代码
flutter代码
import 'package:flutter/cupertino.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class HomePage extends StatefulWidget {
HomePage({Key? key, required this.url}) : super(key: key);
String url;
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool _loadPage = true;
InAppWebViewController? webViewController;
// GlobalKey可以获取到对应的Widget的State对象!
// 当我们页面内容很多时,而需要改变的内容只有很少的一部分且在树的底层的时候,我们如何去实现增量更新?
// 通常情况下有两种方式,第一种是通过方法的回调,去实现数据更新,第二种是通过GlobalKey,
final GlobalKey webViewKey = GlobalKey();
// webview配置
InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
// 跨平台配置
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
mediaPlaybackRequiresUserGesture: false,
),
// android平台配置
android: AndroidInAppWebViewOptions(
//支持HybridComposition
useHybridComposition: true,
),
// ios平台配置
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
),
);
@override
Widget build(BuildContext context) {
return Container(
child: InAppWebView(
key: webViewKey,
initialFile: 'lib/assets/html/demo.html',
// initialUrlRequest: URLRequest(url: Uri.parse("https://inappwebview.dev/")),
initialOptions: options,
// InAppWebview中获取InAppWebViewController
onWebViewCreated: (InAppWebViewController controller) {
webViewController = controller;
// 注册一个JS处理方法,名称为myHandlerName
controller.addJavaScriptHandler(
handlerName: 'myHandlerName',
callback: (args) {
// 打印js方传递过来的参数
print('args=js方传递过来的参数============================$args');
// 传给js方的参数
return "flutter给js的数据";
});
},
onConsoleMessage: (controller, consoleMessage) {
//这里是打印来自于js的conse.log打印
print("consoleMessage==来自于js的打印====$consoleMessage");
},
onPageCommitVisible: (inAppWebViewControlle, uri) async {
if (_loadPage) {
setState(() {
_loadPage = false;
});
var fileHtmlContents = await webViewController!.getHtml();
fileHtmlContents = fileHtmlContents!.replaceAll(
'<div class="flutter-view"></div>',
"<div class='flutter-view' style='width: 200px; height: 200px;background-color: green;'>12345678910</div>",
);
webViewController!.loadData(data: fileHtmlContents);
}
},
),
);
}
}
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>demo</title>
<script>
// 下面的"flutterInAppWebViewPlatformReady"为固定写法
// "myHandlerName"与flutter中注册的JS处理方法名称一致
window.addEventListener("flutterInAppWebViewPlatformReady", function () {
window.flutter_inappwebview
.callHandler("myHandlerName", "这里是传给flutter的参数")
.then(function (res) {
console.log("res========flutter给html的数据", res);
})
})
</script>
</head>
<body>
<h1>我是一个demo</h1>
<h1>我是一个html文件</h1>
<h1>我想展示在flutter应用里</h1>
<div class="flutter-view"></div>
</body>
</html>
5.常见问题
下载完插件直接运行会报错,需要根据报错提示修改配置;
1)在项目文件-->android-->app-->build.gradle中,变量值固定数值参考报错信息,建议为大于等于报错提示信息中的数值。
android {
compileSdkVersion 31
defaultConfig {
minSdkVersion 23
targetSdkVersion 28
}
}