flutter_inappwebview+getx 实现H5通讯
前言
在实际的APP开发过程中,我们有很多业务都是使用H5来实现的,使用H5就需要用到webview的功能,这个组件实际上就是在APP中加载H5页面并且完成一些H5页面和APP的交互,我十分推荐使用flutter_inappwebview插件来处理webview的问题,它的功能比较强大,我在这里仅做一点点在getx中使用的介绍
引入
官方地址:pub.dev/packages/fl…
文档地址:inappwebview.dev/docs/webvie…
flutter pub add flutter_inappwebview
// 或者在pubspec.yaml文件中添加
flutter_inappwebview: ^6.0.0
插件使用
1. 创建html文件
我们需要加载的H5页面可以使用任意前端技术栈完成,最终只需要加载一个链接即可,我这里就使用最简单的html单文件添加serverlive完成访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>这是webview的内置页面</title>
</head>
<style>
.box {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
button {
width: 100px;
height: 30px;
margin: 20px 0;
}
</style>
<body>
<div class="box">
<p>这是H5页面</p>
</div>
</body>
</html>
建议使用vscode 默认的live-server插件将网页打开,当然直接打开html的地址也没有问题,这里我使用vscode的server打开获得这个地址:[http://127.0.0.1:5500/lib/pages/webview/webview.html](http://127.0.0.1:5500/lib/pages/webview/webview.html)
,如下所示:
2. Flutter代码集成webview
2.1. 页面渲染view集成
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:miaohu_course/common/index.dart';
import 'package:miaohu_course/common/widgets/index.dart';
import 'package:url_launcher/url_launcher.dart';
import 'index.dart';
class WebviewPage extends GetView<WebviewController> {
const WebviewPage({super.key});
// 主视图
Widget _buildView() {
return Stack(
children: [
InAppWebView(
key: controller.webViewKey,
initialUrlRequest: URLRequest(
url: WebUri(
"http://127.0.0.1:5500/lib/pages/webview/webview.html")),
onWebViewCreated: (webViewcontroller) async {
controller.setWebViewController(webViewcontroller);
print(await webViewcontroller.getUrl());
},
onLoadStop: (webViewcontroller, url) {
controller.onloadFunction(webViewcontroller);
},
initialSettings: controller.settings,
shouldOverrideUrlLoading: (controller, navigationAction) async {
var uri = navigationAction.request.url!;
if (![
"http",
"https",
"file",
"chrome",
"data",
"javascript",
"about"
].contains(uri.scheme)) {
if (await canLaunchUrl(uri)) {
// Launch the App
await launchUrl(
uri,
);
// and cancel the request
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
onProgressChanged: (webviewController, progress) {
controller.setProgress(progress);
},
// initialOptions: ,
),
],
);
}
@override
Widget build(BuildContext context) {
return GetBuilder<WebviewController>(
init: WebviewController(),
id: "webview",
builder: (_) {
return Scaffold(
appBar: AppBar(title: const Text("webview")),
body: SafeArea(
child: _buildView(),
),
floatingActionButton: <Widget>[
SizedBox(
height: 10.h,
),
IconButton(
color: Colors.white,
onPressed: () {
// controller.onclickDownloadFile();
},
icon: const Icon(Icons.replay_outlined))
.backgroundColor(const Color(0xFF9982FF))
.clipOval()
].toColumn().height(100.h).marginOnly(bottom: 50.h));
},
);
}
}
2.2. webview属性
我们简单看一下webview提供的属性,有以下几点
- initialUrlRequest:加载url的请求
- initialUserScripts:初始化设置的script
- initialOptions:初始化设置的配置
- onWebViewCreated:webview创建后的callback回调
- onTitleChanged:网页title变换的监听回调
- onLoadStart:网页开始加载
- shouldOverrideUrlLoading:确定路由是否可以替换,比如可以控制某些连接不允许跳转。
- onLoadStop:网页加载结束
- onProgressChanged:页面加载进度progress
- onLoadError:页面加载失败
- onUpdateVisitedHistory;更新访问的历史页面回调
- onConsoleMessage:控制台消息,用于输出console.log信息
2.3. APP端向H5传递专属信息
先创建controller
import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:get/get.dart';
class WebviewController extends GetxController {
WebviewController();
GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
InAppWebViewSettings settings = InAppWebViewSettings(
clearCache: true,
cacheEnabled: false,
mediaPlaybackRequiresUserGesture: false,
allowsInlineMediaPlayback: true,
iframeAllow: "camera; microphone",
iframeAllowFullscreen: true);
int progress = 0;
_initData() {
update(["webview"]);
}
void onTap() {}
// @override
// void onInit() {
// super.onInit();
// }
@override
void onReady() {
super.onReady();
_initData();
}
Future onloadFunction(InAppWebViewController webViewcontroller) async {
var source = GetPlatform.isAndroid
? "window.top.localStorage.setItem('H5_key','111111')"
: "window.localStorage.setItem('H5_key','1111111')";
await webViewcontroller.evaluateJavascript(
source: source,
);
}
}
我们在onLoadStop之后给H5页面设置一个缓存数据存储在localStroage中,我们可以在H5中使用Vconsole插件,如下我们便获得了APP传递的数据。
2.4. H5向APP传递数据
2.4.1. 传递数据触发弹窗事件
在H5中向App传递数据主要是我们使用的flutter_inappwebview 在H5的window对象中混入了flutter_inappwebview属性,因此我们可以使用window.flutter_inappwebview.callHandler
来向APP传递数据,如下
// 在html标签中添加按钮
<button onclick="click1()">点击触发事件</button>
// 在script标间中触发事件
function click1() {
window.flutter_inappwebview.callHandler("clickEvent", {
data: "11111",
});
}
然后再APP端进行监听
Future setWebViewController(InAppWebViewController controller) async {
webViewController = controller;
controller.addJavaScriptHandler(
handlerName: "clickEvent",
callback: (args) async {
if (args[0]["data"] != null) {
showToastView(args[0]["data"]);
}
});
}
这样我们就将H5中的 11111 传递给APP 并进行了弹窗展示
2.4.2. 传递事件后获取处理结果
很多时候我们在H5点击触发APP事件之后还需要等待APP返回数据,比如H5的上传下载在APP中需要使用APP的文件操作才能处理,我这里只展示一个简单的事件传递之后获取结果的例子,代码如下
H5代码:
// html标签内的代码
<button onclick="click4()">获取APP数据</button>
// script 标签的代码
function click4() {
window.flutter_inappwebview.callHandler("getText").then(res => {
document.getElementById("textButton").innerText = res;
});
}
APP内部代码
controller.addJavaScriptHandler(
handlerName: "getText",
callback: (args) async {
return "这是APP返回的消息";
});
这样就完成了如下的操作,我们获取了APP 的数据,并且修改了H5的值,这样就完成了H5从APP获取参数的功能
总结
目前使用flutter_inappwebview完成了大部分我们在软件开发中的H5和APP交互的功能,选择这个插件的原因就是因为整体的使用十分的简单,能够更加快速高效的进行开发,但是在我们实际使用下来,插件的坑也有,比如缓存清理不及时或者设置清理之后整个的回收机制比较迷茫,需要以来H5的一部分缓存处理机制来处理,但是总体而言,还是非常好用的。
代码仓库:
当前全部代码已上传git:github.com/lixiaoblack…
转载自:https://juejin.cn/post/7357689320591261722