Flutter Web - 分析在 iOS Safari 上侧滑返回异常的问题

4,436 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

Flutter Web 系列

《Flutter Web - 让 Web 与 APP UI 一致的另一种可能》 

《Flutter Web - 优雅的兼容 Flutter App 代码》

(日新计划的最后一更,献给这个天坑)[真·狗头]。

最近一直在调试 Flutter for Web 项目,已经到了最后小问题调整的阶段。但这些小问题有的确实十分的棘手,而且以 iOS Safari 的居多。比如前几天发的 《Flutter Web - 如何适配 iphone 安全区域》 就是底部栏适配 Safari 出现的问题。

必须先吐槽 Flutter 官方,这是有多瞧不上 iOS Safari [狗头*10086] ...

问题描述

直接看录的 Demo 视频(伪,掘金还不支持上传视频,转成 gif):

RPReplay_Final1671519091.gif

找到一个(不)合适的滑动方式(不正常的概率还是比较大的),就可以把页面变得要多奇怪就有多奇怪,像是抽风了一样,但如果是使用浏览器的返回或者导航栏的返回都是正常的 ...

实践过程

其实这个问题在 Flutter 多引擎渲染组件开发的已经注意到了,只不过一直觉得是小问题,所以拖到项目上把 App 页面渲染到 Web 上的调试阶段时,才准备处理一下。

禁用侧滑返回

最开始并没有想到是 Safari 本身的问题,只觉得是 Flutter 路由动画上有问题,有问题就想着先禁用掉侧滑返回看看,所以直接在根节点加上 WillPopScope

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: WillPopScope(
        onWillPop: () async => false,
        child: ...,
      ),
    );

然并卵,禁用不了侧滑返回,该什么样就什么样 ...

与 Android 对比

想到跟 Android 对比下,但手上没有真机,就在公司的真机平台试了试

image.png

完全没办法侧滑,说明 WillPopScope 控制还是有效的,但对 iOS 浏览器没效果。

寻找原因

这时可以确认应该是在 iOS 浏览器的适配上有问题,这时候就只能 Google 来寻找解决方案了,感觉应该也是一个普适性问题,但一开始确实没搜到,搜索姿势不对,侧滑返回要搜 “swiped back” 果然 github 上确实有类似的问题,传送门:

github.com/flutter/flu…

github.com/flutter/flu…

github.com/flutter/flu…

都是 open 状态,而且最早的是在2020年就提出来了,评级 P5,根本没有人想去解决(当然,比起 Flutter 那么多高 P 的 issues,可能真的是没工夫处理这种“小问题”)。

里面的评论这里总结下,问题的原因是:在触发到系统的侧滑返回后,Flutter 会重新加载整个 Web 应用,而且这个加载过程并不是正常的,所以有各种各样的奇怪现象。

临时解决方式

那如何破局?评论里找到一个方法,通过拦截边缘的响应事件,来减少出现的频率。

      window.addEventListener("load", function () {
        var loading = document.querySelector("#loading");
        _flutter.loader
          .loadEntrypoint({
            serviceWorker: {
              serviceWorkerVersion: serviceWorkerVersion,
            },
          })
          ....
          .then(function (_) {
            const flutterRoot = document
              .getElementsByTagName("flt-glass-pane")
              .item(0);
            flutterRoot.addEventListener("touchstart", (e) => {
              if (e.pageX > 24 && e.pageX < window.innerWidth - 24) return;
              e.preventDefault();
            });
          });
      });

flt-glass-pane 标签增加 touchstart 监听,如果手势起点在左右两边 24 边距内则忽略。

这方法笔者加了试了,确实可以降低概率,但还是不能完全避免。而且如果界面上有边缘操作,那可能会被阻挡 ...

后续

如果是在自己的 App 上加载的话,就很容易禁用掉侧滑返回。

但这个 Wap 项目最后是在微信小程序中加载,所以想着我们在微信小程序中禁用掉侧滑返回不就好了,找到 disableSwipeBack 禁用方式,但用不了了:

image.png

微信:我支持禁用了侧滑返回,过了 0.0.5 个版本,我又不支持了,我任性,你气不气?

image.png

所以至此,只能用上述的临时解决方式,以及把 SPA 的 Flutter Web 开始拆分成多个 web-view 加载来尽可能减少用户误操作的概率了 ...

但回过头来想一想,同样是 SPA,为什么 Vue / React 没有这种问题?感觉 Flutter for Web 应该也有完全解决的方式,但需要有时间去深追源码了。


感谢阅读,如果对你有用请点个赞 ❤️

中秋节GIF动图引导在看提示.gif