前言
flutter
开发过程中难免会用到 WebView,且有时分还会或许需求与 js 交互,而体系给咱们供给一个一个WebView库房,现在运用杰出(前面版本的许多问题根本都现已处理,能够定心食用)
官方库房地址
但仅仅是官方的事例,很多地方读者也不明白或许打不通,本篇文章便是打通后的成果,且代码库房有两个端的代码,能够测验,因此能够定心食用,且里边还加了进展条,作用杠杠的
事例地址(包含react测试用例和flutter事例)
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事例详解
话不多说,直接上代码,下面有各个参数的阐明,一同也会具体介绍几个参数
WebView(
//url
initialUrl: widget.url,
//允许js履行,默认不允许,显现静态页面
javascriptMode: JavascriptMode.unrestricted,
//侧边手势是否敞开,敞开后从左往右划动能够退出当时页面
gestureNavigationEnabled: true,
//webview创立完结后的回调,只会回调一次
onWebViewCreated: (WebViewController webViewController) {
//webView创立完结,保存以便于后续时分
_controller = webViewController;
},
//页面开端加载
onPageStarted: (String url) {
print('Page started loading: $url');
},
//页面加载完毕
onPageFinished: (String url) async {
print('Page finished loading: $url');
//顺表加载一个导航
final title = await _controller?.getTitle();
if (title != null) {
setState(() {
webTitle = title;
});
}
},
//进展条刚好再开端和结束之间
onProgress: (int progress) {
print('WebView is loading (progress : $progress%)');
setState(() {
progessValue = progress / 100.0;
});
},
//路由托付(导航署理),能够经过阻拦跳转url来完成,能够跳转flutter或许交互,也能够传递参数
navigationDelegate: (NavigationRequest request) {
print(request.url);
if (request.url.startsWith('https:///post/7155821382742310920')) {
print("进入了我的侧边栏文章,暂时不作处理,就符号一下");
}
// else if (request.url.startsWith('https:///post/')) {
// //阻止进入其他文章,就只能进入我上面一篇文章
// print('blocking navigation to $request}');
// return NavigationDecision.prevent;
// }
//其他恳求正常跳转
return NavigationDecision.navigate;
},
//JavascriptChannel来进行交互
javascriptChannels: <JavascriptChannel>{
//参数为Set,能够传入多个JavascriptChannel,依据name作为哈希值
JavascriptChannel(
name: 'flutterMessage',
onMessageReceived: (JavascriptMessage message) {
print("flutter接纳到了web端发送过来的flutterMessage音讯${message.message}"); //js发送过来的信息
},
),
JavascriptChannel(
name: 'flutterOrder',
onMessageReceived: (JavascriptMessage message) {
//js发送过来的信息,咱们能够进行处理或许跳转等
print("flutter接纳到了web端发送过来的flutterOrder音讯${message.message}"); //js发送过来的信息
_controller?.loadUrl("https:///ios");
},
),
},
),
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 信息啦
initialCookies: const <WebViewCookie>[
//一般一个网页用同一组cookie,支持多组cookie
WebViewCookie(
name: "token", //cooke键值
value: "1293172938712931798", //cookie值
domain: ".", //域名
//path: "/",//一般页面都是运用一个cookie,一般'/'运用到整个运用
),
WebViewCookie(
name: "username", //cooke键值
value: "www.baidu.com", //cooke值
domain: ".", //域名
//path: "/",//一般页面都是运用一个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
运用了
_controller?.loadUrl("https:///ios");
navigationDelegate路由托付
经过路由托付,咱们能够直接操控页面是否进行跳转,一同也能够接纳 web 页面传递过来的信息,如下所示
//路由托付(导航署理),能够经过阻拦跳转url来完成,能够跳转flutter或许交互,也能够传递参数
navigationDelegate: (NavigationRequest request) {
print(request.url);
if (request.url.startsWith('https:///post/7155821382742310920')) {
print("进入了我的侧边栏文章,暂时不作处理,就符号一下");
}else if (request.url.startsWith('https:///post/')) {
//阻止进入其他文章,就只能进入我上面一篇文章
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
//其他恳求正常跳转
return NavigationDecision.navigate;
},
flutter和web交互(JavascriptChannel)
flutter和web交互
其实也很简单,经过web给出的JavascriptChannel
进行交互就能够了,如下所示
设置JavascriptChannel
//JavascriptChannel来进行交互
javascriptChannels: <JavascriptChannel>{
//参数为Set,能够传入多个JavascriptChannel,依据name作为哈希值
JavascriptChannel(
name: 'flutterMessage',
onMessageReceived: (JavascriptMessage message) {
print("flutter接纳到了web端发送过来的flutterMessage音讯${message.message}"); //js发送过来的信息
},
),
JavascriptChannel(
name: 'flutterOrder',
onMessageReceived: (JavascriptMessage message) {
//js发送过来的信息,咱们能够进行处理或许跳转等
print("flutter接纳到了web端发送过来的flutterOrder音讯${message.message}"); //js发送过来的信息
_controller?.loadUrl("https:///ios");
},
),
},
运用了 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
项目都要一同运转
才能够哈