Flutter使用webview

405 阅读2分钟

前言

在项目开发中,由于官方没有直接提供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);
    }
  }