前言
在项目开发中,由于官方没有直接提供WebView控件,如果涉及到网页加载的地方,就需要用到第三方插件,这里推荐使用webview_flutter,它是Flutter官方开发和维护的网页加载插件库。
版本V2.8.0 技术实现
项目依赖
dependencies:
webview_flutter: ^2.8.0
初始化Cookie
import 'package:cookie_jar/cookie_jar.dart';
import 'package:webview_flutter/webview_flutter.dart';
/// 初始化cookie
Future<List<WebViewCookie>> initCookie(String url) async {
List<WebViewCookie> cookieList = [];
bool domain = '是否为自己网站上的域' == '是' ? true :false;
if (domain) {
// 获取cookie
List<Cookie> list = await cookieManager.cookieJar.loadForRequest(Uri.parse(url));
StringBuffer buffer = StringBuffer();
for (Cookie cookie in list) {
WebViewCookie webViewCookie = WebViewCookie(
name: cookie.name,
value: cookie.value,
domain: '${cookie.domain}',
path: '${cookie.path}');
cookieList.add(webViewCookie);
CookieManager().setCookie(webViewCookie);
String value = '''
document.cookie = '${cookie.name}=${cookie.value}';
document.cookie = 'Domain=${cookie.domain}';
document.cookie = 'Path=${cookie.path}';
document.cookie = 'Expires=${cookie.expires}';
''';
buffer.write(value);
print('WebView initCookie: ${webViewCookie.toJson().toString()}');
}
final String cookie = buffer.toString();
webViewController?.runJavascript(cookie);
}
return cookieList;
}
初始化WebView
_body() {
return FutureBuilder(
future: initCookie('https://www.xxx'),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// 请求完成
if (!snapshot.hasError && null != snapshot.data) {
// 请求成功
List<WebViewCookie> cookies = snapshot.data;
return WebView(
userAgent: 'xxx',
// 初始化网址(如果需要带请求头,请在创建完WebView之后再携带请求头加载url)
initialUrl: 'https://www.xxx',
// 初始化Cookie
initialCookies: cookies,
// js模式:设置不受限制
javascriptMode: JavascriptMode.unrestricted,
// js调用flutter方法监听
javascriptChannels: customizeJavascriptChannels(),
// 是否开启手势缩放,默认开启
zoomEnabled: true,
// 总是允许播放媒体
initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
// 是否允许在 iOS 上内联播放 HTML5 视频,安卓默认允许
allowsInlineMediaPlayback: true,
// 指示水平滑动手势是否会触发后退列表导航,仅适用于 iOS
gestureNavigationEnabled: true,
// 背景颜色
backgroundColor: Colors.white,
onWebViewCreated: (WebViewController webViewController) async {
final userAgent = await webViewController.runJavascriptReturningResult('navigator.userAgent');
print('WebView navigator userAgent: $userAgent');
// 加载Url
bool isHeaders = '是否添加请求头' == '是' ? true :false;
if(isHeaders) {
webViewController?.loadUrl('https://www.xxx', headers: {'key':'value'});
} else {
webViewController?.loadUrl('https://www.xxx');
}
},
navigationDelegate: (NavigationRequest request) async {
final String url = request.url;
print('WebView navigationDelegate:$url');
// 拦截请求,每次网页路由地址发生变化的时候都会触发
if (await customizeNavigationDelegate(url)) {
// 阻止导航
return NavigationDecision.prevent;
}
// 允许导航
return NavigationDecision.navigate;
},
onWebResourceError: ((WebResourceError error) {
// 资源加载失败时触发,返回的数据因平台而异
}),
onPageStarted: (String url) {
// 页面开始加载
},
onProgress: (int progress) {
// 页面加载进度
},
onPageFinished: (String url) {
// 页面完成加载
});
}
}
return Container(
color: Colors.white,
width: double.infinity,
height: double.infinity);
},
);
}
与JS交互
/// 与JS交互
Set<JavascriptChannel> customizeJavascriptChannels() {
return <JavascriptChannel>{
JavascriptChannel(
name: 'webkit',
onMessageReceived: (JavascriptMessage message) {
// 可以通过message.message来获取JS发给我们的数据,接收类型是字符串,如果需要传递复杂的数据,可以通过json字符串来解决
String strJson = message.message;
if (strJson.isNotEmpty) {
Map<String, dynamic> map = json.decode(strJson);
String key =
ObtainValueUtil.getString(map, 'key');
switch (key) {
case 'xxx1':
break;
case 'xxx2':
break;
case 'xxx3':
break;
}
}
})
};
}
拦截请求
/// 拦截请求
Future<bool> customizeNavigationDelegate(String url) async {
if (url.contains('/xxx/xxx1')) {
return true;
} else if (url.contains('/xxx/xxx2')) {
return true;
} else if (url.contains('/xxx/xxx3')) {
return true;
}
return false;
}
回退上一层
/// 返回上一层
goBack(BuildContext context) async {
// 是否可以回退
bool? flag = await webViewController?.canGoBack();
if (null != flag && flag) {
// 回退
webViewController?.goBack();
} else {
Navigator.pop(context);
}
}