flutter-webview_flutter使用以及交互
前言
flutter
开发过程中难免会用到 WebView,且有时候还会可能需要与 js 交互,而系统给我们提供一个一个WebView仓库,目前使用良好(前面版本的诸多问题基本都已经解决,可以放心食用)
但仅仅是官方的案例,很多地方读者也不明白或者打不通,本篇文章就是打通后的结果,且代码仓库有两个端的代码,可以尝试,因此可以放心食用,且里面还加了进度条,效果杠杠的
WebView参数简介
onWebViewCreated
:在 WebView 创建完成后调用,只会被调用一次;initialUrl
:url 不多说;initialCookies
:设置 cookie,web端比较常用,一般用于携带用户令牌javascriptMode
:JS 执行模式(是否允许 JS 执行),默认为JavascriptMode.disable
只能执行静态页面,设置为JavascriptMode.unrestricted
即可解决;gestureNavigationEnabled
:侧边手势是否开启,开启后从左往右划动可以退出当前页面onPageStarted
:页面开始加载onPageFinished
:WebView 加载完毕时的回调onProgress
:进度条百分比回调(返回 int 类型,0~100),当然只是表示静态页的加载进度,里面 js 执行结果未知navigationDelegate
:路由委托(导航代理),可以通过拦截跳转url来实现,可以跳转flutter或者交互,也可以传递参数;javascriptChannels
:JS 和 Flutter 通信的 Channel set;
WebView案例详解
话不多说,直接上代码,下面有各个参数的说明,同时也会详细介绍几个参数
onProgress
进度回调,里面返回的是 0~100
的数字,一般作为百分比使用,当我们进度条的时候,需要合理控制其值
由于下面的进度条值为 0~1
之间,因此系统的回调的值需要除以100
方可使用
//滚动条,用来显示加载进度,下面是线性的,圆形的是CircularProgressIndicator
//可以使用完销毁(本案例就是)
LinearProgressIndicator(
color: Colors.greenAccent,
backgroundColor: Colors.transparent,
value: progessValue,
),
//进度条回调
onProgress: (int progress) {
print('WebView is loading (progress : $progress%)');
setState(() {
progessValue = progress / 100.0;
});
},
initialCookies
设置 cookie
web开发中一般都会用到 cookie
信息,需要登录
方可获取,手机端已经登录的情况,如果访问web
的一些子页面webView
,那就需要携带cookie
信息了,因此需要我们手动传递cookie
信息然后加载 webView
另外,手机一般只有一个用户登录,必要的话,可以将 webView
直接跟自己的用户信息
连接封装到一起,这样就不用每次打开 webView,都要重新填写 cookie 信息啦
WebViewController
WebViewController
是 webView
在使用的过程中非常常用的一个对象,里面有很多的参数,例如:例如滚动到某个位置、判断网页是否能返回、查找页面标题、跳转、设置 cookie 等
这里面我们只介绍是否能返回和找出标题
onWebViewCreated
其为创建 webview 后的回到,我们可以保存 webViewController
//webview创建完成后的回调,只会回调一次
onWebViewCreated: (WebViewController webViewController) {
//webView创建完成
_controller = webViewController;
},
onPageFinished
页面加载完毕后的回调,我们可以在加载完成之后,获取标题,显示到我们的导航上面
//页面加载完毕,会发现我们将方法声明成了异步,这样方便取出title,当然也可以用 then 回调获取
onPageFinished: (String url) async {
print('Page finished loading: $url');
//顺表获取导航标题,返回的是 Future
final title = await _controller?.getTitle();
if (title != null) {
setState(() {
webTitle = title;
});
}
},
goBack返回上一页
当我们web
只有一个页面的时候,我们直接返回退出 web
页面就好了,如果 web
中也有路由和子页面
,我们点击返回的时候,直接退出了整个 web 页面
,那么体验就不是很好了,因此系统给我们提供了 canGoBack
方法,我们可以通过该方法直接获取是否能返回上一页,到 web 跟路由时 就不能返回,走我们的导航就是了
leading: Builder(
builder: (context) {
return IconButton(
onPressed: () {
if (_controller != null) {
_controller?.canGoBack().then((value) {
if (value) {
_controller?.goBack();
}else {
Navigator.of(context).pop();
}
}).catchError((err) {
Navigator.of(context).pop();
});
}else {
Navigator.of(context).pop();
}
},
icon: const Icon(
Icons.arrow_back_ios_new,
color: Colors.white,
),
);
},
),
你可能觉得上面的判断有点多,没办法就是要严谨,下面优化下 onPress
逻辑,下面是不是清晰一些了
//使用闭包或者写外面都行
Future<void> canGoBack() async {
if (_controller != null && await _controller!.canGoBack()) return;
throw Error();
}
canGoBack().then((value) {
_controller?.goBack();
}).catchError((error) {
Navigator.of(context).pop();
});
loadUrl(加载新页面)
如果想无缝跳转到其他 web
页面,可以采用 loadUrl
方法,这样就可以无缝衔接我们的多个 web
应用了
navigationDelegate路由委托
通过路由委托,我们可以直接控制页面是否进行跳转,同时也可以接收 web 页面传递过来的信息,如下所示
flutter和web交互(JavascriptChannel)
flutter和web交互
其实也很简单,通过web给出的JavascriptChannel
进行交互就可以了,如下所示
设置JavascriptChannel
使用了 JavascriptMessage
之后,会将 JavascriptChannel
里面的 name
挂载到 web 项目
的 window
上(以 react
为例),让我们看看 react
的代码,其他端也差不多,可以运行一下本案例尝试
而 web
端,通过 postMessage
可以传递消息给 flutter
,那边的回调就能接收到消息了
function App() {
const [message, setMessage] = useState('')
useEffect(() => {
window.flutterMessage.webReceiveMessage = (message) => {
setMessage(message)
}
return () => {
delete window.flutterMessage.webReceiveMessage
}
}, [])
return (
<div className="App">
<div onClick={() => {
window.flutterMessage?.postMessage("发送了FlutterMessage消息给flutter");
}}>点击发送FlutterMessage消息</div>
<div onClick={() => {
window.flutterOrder?.postMessage("发送了FlutterOrder消息给flutter");
}}>点击发送FlutterOrder消息</div>
<div>接收到的message:{message}</div>
</div>
);
}
flutter
主动给 web
端发消息,代码如下
//发送给web端消息,其中 webReceiveMessage 为 web 给 'name' 添加的方法
_controller?.runJavascript('flutterMessage.webReceiveMessage("收到了没")');
通过上面代码可以看到, 在flutter
中设置JavascriptChannel
,会将JavascriptChannel
的name
为对象挂载到 web
的window
上面
web端
:通过 'name' + postMessage
发送消息给flutter
flutter
: 通过 _controller.runJavascript
调用 js
脚本,其中脚本为 'name' + web在name下添加的方法
,就这样直接调用即可
交互原理便是通过 flutter
给 web
端 window
上挂载的同名对象,通过给该对象添加方法,然后主动调用来实现交互
最后
快来尝试一下吧,案例开头也标记了,可以运行一下试试,web
和 flutter
项目都要同时运行
才可以哈
转载自:https://juejin.cn/post/7158076084473298957