likes
comments
collection
share

flutter-webview_flutter使用以及交互

作者站长头像
站长
· 阅读数 77

前言

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案例详解

话不多说,直接上代码,下面有各个参数的说明,同时也会详细介绍几个参数

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 信息啦

WebViewController

WebViewControllerwebView 在使用的过程中非常常用的一个对象,里面有很多的参数,例如:例如滚动到某个位置、判断网页是否能返回、查找页面标题、跳转、设置 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 应用了

navigationDelegate路由委托

通过路由委托,我们可以直接控制页面是否进行跳转,同时也可以接收 web 页面传递过来的信息,如下所示

flutter和web交互(JavascriptChannel)

flutter和web交互其实也很简单,通过web给出的JavascriptChannel进行交互就可以了,如下所示

设置JavascriptChannel

使用了 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,会将JavascriptChannelname为对象挂载到 webwindow上面

web端:通过 'name' + postMessage 发送消息给flutter

flutter: 通过 _controller.runJavascript调用 js 脚本,其中脚本为 'name' + web在name下添加的方法,就这样直接调用即可

交互原理便是通过 flutterwebwindow 上挂载的同名对象,通过给该对象添加方法,然后主动调用来实现交互

最后

快来尝试一下吧,案例开头也标记了,可以运行一下试试,webflutter 项目都要同时运行才可以哈

转载自:https://juejin.cn/post/7158076084473298957
评论
请登录