课程名称:Flutter从入门到进阶 实战携程网App 一网打尽核心技术
课程章节:Flutter进阶实战:App首页功能开发
课程讲师:CrazyCodeBoy
课程内容
在 Flutter 中使用 webview
在 Flutter 中与 H5混合开发也是常用的功能,在 Flutter 中使用的比较多的插件有webview_flutter和flutter_webview_plugin。
- webview_flutter,是官方维护的 WebView 插件,特性是基于原生和 Flutter SDK 封装,继承 StatefulWidget,因此支持内嵌于 flutter Widget 树中,使用比较灵活。
- flutter_webview_plugin,则是基于原生 WebView 封装的 Flutter 插件,将原生的一些基本使用 API 封装好提供给 Flutter 调用,因此并不能内嵌于 Flutter Widget 树中,因此在界面的跳转必须得先释放掉,返回后又要重新初始化。
使用时,在 Android 设备上还会遇到这样的问题,Android9开始谷歌就默认不让开发者访问不安全HTTP内容了,如果非要用HTTP,那必须在networkSecurityConfig里配置cleartextTrafficPermitted才行。具体做法是:需要在AndroidManifest.xml里配置好usesCleartextTraffic和network_security_config。
在flutter项目下创建/android/app/src/main/res/xml/network_security_config.xml文件,填上配置内容
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
然后修改/android/app/src/main/AndroidManifest.xml文件,在application节点加入以下两个属性:
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
之后在控制台执行flutter clean,重新run,就可以看到App里的webview能正常打开HTTP网站了。
Flutter与 H5之间的交互
在Flutter 使用 webview 打开网页后,很多时候还会面临与 H5 进行交互的问题。系统的 webview 主要包括下面的方法:
const WebView({
Key? key,
this.onWebViewCreated, //在WebView创建完成后调用,只会被调用一次
this.initialUrl, //初始load的url
this.initialCookies = const <WebViewCookie>[],
this.javascriptMode = JavascriptMode.disabled, //JS执行模式(是否允许JS执行)
this.javascriptChannels, //JS和Flutter通信的Channel
this.navigationDelegate, //路由委托(可以通过在此处拦截url实现JS调用Flutter部分)
this.gestureRecognizers, //手势监听
this.onPageStarted, //WebView开始加载时的回调
this.onPageFinished, //WebView加载完毕时的回调
this.onProgress, //WebView加载进度的回调
this.onWebResourceError,
this.debuggingEnabled = false,
this.gestureNavigationEnabled = false,
this.userAgent,
this.zoomEnabled = true,
this.initialMediaPlaybackPolicy =
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
this.allowsInlineMediaPlayback = false,
this.backgroundColor,
})
H5调用Flutter中的方法
JS调用Flutter有两种方法:使用javascriptChannels发送消息和使用路由委托(navigationDelegate)拦截url。
使用javascriptChannels发送消息
javascriptChannels参数可以传入一组Channels,可以定义一个_alertJavascriptChannel变量,这个channel用来控制JS调用Flutter中的方法。
Flutter 端实现:
JavascriptChannel _alertJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toast',
onMessageReceived: (JavascriptMessage message) {
showToast(message.message);
});
}
WebView(
javascriptChannels: <JavascriptChannel>[
_alertJavascriptChannel(context),
].toSet(),
;
H5 端实现:
<button onclick="callFlutter()">callFlutter</button>
function callFlutter(){
Toast.postMessage("JS调用了Flutter");
}
在上面的代码中定义了一个_alertJavascriptChannel变量,并给它起了个name叫Toast,这个name属性接收的是一个字符串,它代表了JS调用Flutter时,双方共同商定好了的一个协议,JS通过这个name去post对应的信息给Flutter。onMessageReceived为Flutter接收到了JS的消息之后的回调,通过message.message来获取JS发给flutter的消息内容。JavascriptMessage类暂时只有一个String类型的message成员变量,所以如果需要传递复杂数据,可以通过传递json字符串来解决。
需要注意的是:JavascriptChannel中的name要与JS中的name.postMessage()相对应。
使用路由委托navigationDelegate拦截url
navigationDelegate回调在每次网页路由地址发生变化的时候都会触发,因此可以拦截特定的url来实现JS调用Flutter。
H5 端实现:
<button onclick="callFlutter()">callFlutter</button>
function callFlutter(){
/*约定的url协议为:js://webview?arg1=111&arg2=222*/
document.location = "js://webview?arg1=111&args2=222";
}
Flutter端实现:
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith('js://webview')) {
showToast('JS调用了Flutter By navigationDelegate');
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
print('allowing navigation to $request');
return NavigationDecision.navigate;
},
H5端与 Flutter 端确定好 scheme,在query string上带上想要传递的参数,在Flutter端,可以在navigationDelegate回调中拦截这个 scheme的路由地址。navigationDelegate()方法的不同返回值,告诉WebView怎么处理这个路由:NavigationDecision.prevent(阻止路由替换)、NavigationDecision.navigate:(允许路由替换)。
Flutter调用H5中的方法
在WebView创建完成之后,在 Flutter 端可以拿到一个WebViewController,通过它的evaluateJavascript()方法,可以执行JS语句。
evaluateJavascript()返回值是一个Future,因此可以接收JS的返回值,要注意Android端和iOS端的返回值格式是不一样的,Android端返回的是json字符串,iOS暂时只支持string和string格式的NSArray。
课程总结
这一讲主要介绍了 Flutter 中通过自定义 webview 的方式,实现 Flutter 中加载 H5 的功能。