开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情
Flutter Web 系列
(日新计划的最后一更,献给这个天坑)[真·狗头]。
最近一直在调试 Flutter for Web 项目,已经到了最后小问题调整的阶段。但这些小问题有的确实十分的棘手,而且以 iOS Safari 的居多。比如前几天发的 《Flutter Web - 如何适配 iphone 安全区域》 就是底部栏适配 Safari 出现的问题。
必须先吐槽 Flutter 官方,这是有多瞧不上 iOS Safari [狗头*10086] ...
问题描述
直接看录的 Demo 视频(伪,掘金还不支持上传视频,转成 gif):
找到一个(不)合适的滑动方式(不正常的概率还是比较大的),就可以把页面变得要多奇怪就有多奇怪,像是抽风了一样,但如果是使用浏览器的返回或者导航栏的返回都是正常的 ...
实践过程
其实这个问题在 Flutter 多引擎渲染组件开发的已经注意到了,只不过一直觉得是小问题,所以拖到项目上把 App 页面渲染到 Web 上的调试阶段时,才准备处理一下。
禁用侧滑返回
最开始并没有想到是 Safari 本身的问题,只觉得是 Flutter 路由动画上有问题,有问题就想着先禁用掉侧滑返回看看,所以直接在根节点加上 WillPopScope
。
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: WillPopScope(
onWillPop: () async => false,
child: ...,
),
);
然并卵,禁用不了侧滑返回,该什么样就什么样 ...
与 Android 对比
想到跟 Android 对比下,但手上没有真机,就在公司的真机平台试了试
完全没办法侧滑,说明 WillPopScope
控制还是有效的,但对 iOS 浏览器没效果。
寻找原因
这时可以确认应该是在 iOS 浏览器的适配上有问题,这时候就只能 Google 来寻找解决方案了,感觉应该也是一个普适性问题,但一开始确实没搜到,搜索姿势不对,侧滑返回要搜 “swiped back” 果然 github 上确实有类似的问题,传送门:
都是 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
禁用方式,但用不了了:
微信:我支持禁用了侧滑返回,过了 0.0.5 个版本,我又不支持了,我任性,你气不气?
所以至此,只能用上述的临时解决方式,以及把 SPA 的 Flutter Web 开始拆分成多个 web-view 加载来尽可能减少用户误操作的概率了 ...
但回过头来想一想,同样是 SPA,为什么 Vue / React 没有这种问题?感觉 Flutter for Web 应该也有完全解决的方式,但需要有时间去深追源码了。
感谢阅读,如果对你有用请点个赞 ❤️