博文所用 Flutter SDK:2.2.3,Dart SDK:2.13.4,get: 4.3.8。


文章目录

  • 一:问题描述
  • 二:解决方案
  • 三:源码分析之《如何解决 Dialog 弹窗二次跳转路由异常的问题》
  • 四:源码分析之《为什么在页面中没有这个问题在 Dialog 弹窗中却有》


一:问题描述

之前偶然间发现的一个问题,特此记录下。

上架小米商店的时候,被反馈在用户首次进入应用时要有隐私协议的弹窗,然后就给加了一个,点击《用户协议》时也能正常跳转到相应的 Web 页,以为这样就大功告成了,如下图所示




ios 跳转到TestFlight下载 testflight 不跳转_ios 跳转到TestFlight下载


自己偶然间在测试的时候,当我在弹窗首次弹出后,第一次点击链接可以正常跳转,退出 Web 页再次点击时却没有任何反应,这是为什么呢?

断点调试了下,发现了问题的根本所在。

二:解决方案

设置 Get.toNamed() 方法的属性 preventDuplicates 为 false 即可,如下代码所示

/// 跳转到《用户协议》网页
  void _toAgreementPage() {
    Get.toNamed(
      AppRoutes.WEB,
      arguments: WebModel(title: "《用户协议》", url: agreementUrl, isLocal: false),
      preventDuplicates: false, // “防止重复”设置为 false
    );
  }

然后问题得到解决,这个不仅针对 Dialog,也适合 Snackbar、BottomSheet 等方式。

三:源码分析之《如何解决 Dialog 弹窗二次跳转路由异常的问题》

有些同学喜欢打破沙锅问到底,想知道问题是解决了,但是为什么呢?那咱就源码分析走起。

首先通过断点调试来看下 Get.toNamed() 方法的源码,如下图所示

ios 跳转到TestFlight下载 testflight 不跳转_flutter_02

由图可知,toNamed() 方法上方注释的意思是

  • 默认情况下,GetX 会阻止跳转到已经进入的路由。
  • 如果你想解除这个限制,设置属性 preventDuplicates 为 false 即可。

由断点的位置可知,此时 preventDuplicates 为 true,又能进入到此判断,说明 page == currentRoute 条件也成立,也就是说当前要跳转的是已经进入的路由。

方法返回了 null ,所以在 Dialog 中再次点击链接跳转 Web 页的时候没有任何的反应。

我们只需要设置 preventDuplicates 为 false,条件不成立了,自然进入到了后面的判断。

四:源码分析之《为什么在页面中没有这个问题在 Dialog 弹窗中却有》

一:当路由进栈时

我们先来看一个类 GetObserver ,该类继承自 NavigatorObserver 类,作用是监听页面跳转。像平常用到的 Toast 等也都会继承这个类, GetObserver 类的源码如下图所示

ios 跳转到TestFlight下载 testflight 不跳转_ios 跳转到TestFlight下载_03

当我点击《用户协议》链接跳转到 Web 页的时候,由红色方框选中部分可知,只有 PageRoute 类型的才允许修改当前路由 current 字段的值,所以此时会更新。

这也是为什么从 Dialog 弹窗进入到新页面的时候没什么问题。

二:当路由出栈时

如下图所示

ios 跳转到TestFlight下载 testflight 不跳转_源码分析_04

当我点击 Web 页的返回按钮退出当前页面时,由红色方框选中部分可知,只有 PageRoute 类型的才允许修改当前路由 current 字段的值,而我们是从 Dialog 弹窗进入的,上一个页面的类型是 GetDialogRoute,不满足更新 current 的条件。

所以虽然我们的确是退出了 Web 页,但此时 current 的值并没有被更新,还是 /web,也就是眼睛看到的是弹窗,但程序认为你在 Web 页,这就造成了同个页面无法跳转的问题。

至此,关于在 Flutter 中使用 Get 插件在 Dialog 弹窗中不能二次跳转路由的问题,便介绍到这里。

最后放一张 get 对当前路由类型判断的类,如下图所示

ios 跳转到TestFlight下载 testflight 不跳转_源码分析_05

由图可知

  • Dialog 类型是 GetDialogRoute,继承自 PopupRoute。
  • Snackbar 类型是 SnackRoute,继承自 OverlayRoute。
  • BottomSheet 类型是 GetModalBottomSheetRoute,继承自 PopupRoute。
  • Page 类型是GetPageRoute,继承自 PageRoute。

你的问题得到解决了吗?欢迎在评论区留言。