Flutter 插件:WebView与H5页面混合开发(flutter_webview_plugin)

Flutter 插件:WebView与H5页面混合开发flutter_webview_plugin

岁月是什么?无关春秋,只在心态,人生怎么活?恰似三十未满。化解内心的消极,成全生活的信念,充实幸福的内涵,不以物喜,不以己悲,这是一种生存的气魄,也是生命良好的觉悟,更是每个人在人生路上,都应该表现出来的一种生命品质。

废话不多说,先来康康今天的效果图~

效果图(1.1):
在这里插入图片描述
老思路,先来分析一下:

  • 在界面上有5个按钮,点击每个按钮跳转到对应的布局
  • 点击H5页面的返回按键,返回到Flutter页面

flutter_webview_plugin引用

官方文档 flutter_webview_plugin

在pubspec.yaml下添加依赖,然后Pubget即可

dependencies:
  flutter_webview_plugin: ^0.3.11

代码图(2.1)
在这里插入图片描述
要是用的话添加导包:

import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';

好了,到了今天的正文环节

WebView基础使用


/// WebView使用flutter_webview_plugin插件
/// https://pub.dev/packages/flutter_webview_plugin
// ignore: must_be_immutable
class LocalNavWebWidget extends StatefulWidget {
  String title;
  String url;
  
  LocalNavWebWidget(this.url, this.title);
  @override
  _LocalNavWebWidgetState createState() =>_LocalNavWebWidgetState(title: title, url: url);
}

class _LocalNavWebWidgetState extends State<LocalNavWebWidget> {
  String url;
  String title;
  _LocalNavWebWidgetState({this.url, this.title});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ///隐藏Debug标志
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Container(
              child: WebviewScaffold(
                url: url,
                   appBar: AppBar(
		            title: Text(title),
		          ),
                //当WebView没加载出来前显示
                initialChild: Container(
                  color: Colors.white,
                  child: Center(
                    child: Text("正在加载中...."),
                  ),
                ),
              ),
            )),
    );
  }
}

跳转到WebView页面

Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) {
          return LocalNavWebWidget("https://m.ctrip.com/webapp/you/place/2.html?ishideheader=true&secondwakeup=true&dpclickjump=true&allianceid=66672&sid=1693366&from=https%3A%2F%2Fm.ctrip.com%2Fhtml5%2F",
          "百度");
        }));

这段代码很好理解:

通过Navigator跳转到WebView页面,传递2个参数

  • 传递参数一:Url
  • 传递参数二:title

然后通过 WebviewScaffold() 来跳转到H5页面

来康康效果:

效果图(1.2):
在这里插入图片描述
可以看到,效果是完成了,也能返回到Flutter页面

但是,这也太丑了吧…

接下来,咋们吧AppBar()取消

代码就少了一行AppBar(),就不看代码了,直接看效果图:

效果图(1.3);
在这里插入图片描述
问题又来了,H5页面跑到了状态栏的下面,这样对于我这种手指头粗糙的糙汉子来说太不友好了,根本点不到…

接下来通过代码让H5页面往下移动一下:

import 'dart:ui';//window导入
//获取的是状态栏的高度
MediaQueryData.fromWindow(window).padding.top)

然后设置padding即可

   @override
    Widget build(BuildContext context) {
      return MaterialApp(
        home: Scaffold(
            body: Container(
          /**
               * MediaQueryData.fromWindow(window).padding.top)获取的是状态栏高度
               * 需导入import 'dart:ui';
               */
          padding:
              EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top),
          child: WebviewScaffold(
           	......
          ),
        )),
      );
    }

效果图(1.5):

在这里插入图片描述
看到这里,上一个问题H5页面被状态栏覆盖掉解决了

但是又有了新的问题,点击返回的时候,是返回的H5页面的首页.并没有返回到Flutter页面的首页…

不用着急,您往下看

H5返回Flutter首页

第一步,对页面发生改变监听

 StreamSubscription<WebViewStateChanged> _stateChanged;
 
  final flutterWebviewPlugin = new FlutterWebviewPlugin();
  
	//页面导航的状态
    _stateChanged = flutterWebviewPlugin.onStateChanged.listen((event) {
      print("SZJstartLoadUrl${event.url}");
    });

当页面发生改变的时候,会调用onStateChanged.listen()这个方法

返回的是当前的状态,通过event.url可以看到当前的接口

代码图(2.2):
在这里插入图片描述

当点击返回按钮的时候,页面发生了改变,所以会调用onStateChanged.listen()这个方法,咋们只需要判断如果返回的是H5页面,则直接返回到Flutter页面即可,这里有点点绕,大家不用着急,跟着我继续往下看


 StreamSubscription<WebViewStateChanged> _stateChanged;
 //页面导航的状态
    _stateChanged = flutterWebviewPlugin.onStateChanged.listen((event) {
      print("SZJstartLoadUrl${event.url}");
      switch (event.type) {
        case WebViewState.shouldStart:
          break;
        case WebViewState.startLoad:
          if (_isToFlutter(event.url)) {
            Navigator.pop(context);
          }
          break;
        case WebViewState.finishLoad:
          break;
        case WebViewState.abortLoad:
          break;
      }
    });

通过判断event.type的类型,并在WebViewState.startLoad中监听:

//这个是H5要返回的页面
 List<String> _urlList = [
    "https://m.ctrip.com/html5/",
  ];


 _isToFlutter(String url) {
    //默认不反悔H5页面
    bool isContaion = false;
    _urlList.forEach((element) {
      //判断接口是否相同 相同则返回H5页面
      if (url?.startsWith(element)) {
        isContaion = true;
      }
    });
    return isContaion;
  }

简单点来说就是:

Flutter页面跳转到H5页面A

H5页面A点击返回按钮会返回到H5的首页B

当页面发生变化的时候会响应.onStateChanged.listen((event){}

event.url会弹出当前页面的接口

咋们只需要吧点击返回按钮时

H5页面A返回到H5的首页B记录下来,

并且通过与当前页面的接口判断,如果记录的接口和当前返回的接口是同一个,则直接调用Navigator.pop(context);返回到Flutter页面即可

补充:
WebView还提供了很多的监听,常用的有

  • 返回当前接口监听:
	  StreamSubscription<String> _urlChanged;
	  
    _urlChanged = flutterWebviewPlugin.onUrlChanged.listen((String url) {
      print("SZJ_urlChanged$url");
    });
    
  • 网络错误等情况返回监听
  StreamSubscription<WebViewHttpError> _httpErro;
  
	 _httpErro = flutterWebviewPlugin.onHttpError.listen((event) {
      print("SZJHttpErro网络错误");
    });

这些就不带大家演示了,因为我要下班啦, 哈哈哈

最后一点,朋友们一定要养成习惯,在页面销毁的时候,销毁掉这些用过的东西哦~


  @override
  void dispose() {
    super.dispose();
    _urlChanged.cancel();
    _stateChanged.cancel();
    _httpErro.cancel();
    flutterWebviewPlugin.dispose();
  }

当然了,上面这部分是比较复杂的方法,还有一种简单的方法:

H5页面监听

 child: WillPopScope(
                onWillPop: () {
                  Navigator.of(context).pop();
                },
                child: WebviewScaffold(
                  url: url,
                  ///是否缩放
                  withZoom: true,
                  //是否缓存
                  withLocalStorage: true,
                  //默认状态
                  hidden: true,
                  //这三个参数解决的是在android端网页自动放大问题
                  useWideViewPort: true,
                  displayZoomControls: true,
                  withOverviewMode: true,
                  //当WebView没加载出来前显示
                  initialChild: Container(
                      color: Colors.white,
                      child: Column(
                        //居中
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          LoadingUtil.loading(context),
                          Center(
                            child: Text("正在加载中...."),
                          ),
                        ],
                      )),
                ),
              ))),

可以用WillPopScope包裹WebviewScaffold

必写两个参数:

  • 参数一: child 子Widget
  • 参数二:onWillPop()按钮返回监听

直接在onWillPop中通过

 Navigator.of(context).pop();

返回即可.

完整代码

原创不易,您的点赞就是对我最大的支持,留下您的点赞吧~

在这里插入图片描述


版权声明:本文为weixin_44819566原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。