You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter WebView结合GoRouter(Navigation 2.0):如何处理返回键点击

解决GoRouter(Navigator 2.0)中WebView返回键优先级问题

在Navigator 2.0(如GoRouter)环境下,旧的WillPopScope不再生效,默认返回键会直接触发当前路由弹出,导致WebView内的页面回退需求被忽略——用户在WebView跳转后点返回键,会直接回到上一个Flutter页面,而不是WebView的上一页。

以下是两种可行的解决方案:

方案一:使用PopScope(Flutter 3.10+ 推荐)

PopScope是Flutter官方推出的替代WillPopScope的组件,完美适配Navigator 2.0生态。在包含WebView的页面中嵌套PopScope,自定义返回键逻辑:

class WebViewPage extends StatefulWidget {
  final String url;
  const WebViewPage({super.key, required this.url});

  @override
  State<WebViewPage> createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  late final WebViewController _webController;

  @override
  void initState() {
    super.initState();
    _webController = WebViewController()
      ..loadRequest(Uri.parse(widget.url))
      ..setNavigationDelegate(NavigationDelegate(
        onPageFinished: (_) => setState(() {}),
      ));
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      // 阻止默认路由弹出行为
      canPop: false,
      onPopInvoked: (bool didPop) async {
        // 优先检查WebView是否可回退
        if (await _webController.canGoBack()) {
          _webController.goBack();
        } else {
          // WebView无历史页面时,再退出当前路由
          if (context.mounted) {
            context.pop();
          }
        }
      },
      child: Scaffold(
        appBar: AppBar(title: const Text("网页")),
        body: WebViewWidget(controller: _webController),
      ),
    );
  }
}

逻辑说明:

  1. 设置canPop: false禁用默认的路由弹出,将返回键逻辑完全交由onPopInvoked处理。
  2. 在onPopInvoked中先调用_webController.canGoBack()判断WebView是否有历史页面:
    • 有历史页面则执行_webController.goBack()让WebView回退。
    • 无历史页面时,再调用context.pop()退出当前Flutter路由。

方案二:利用GoRouter的onExit回调

如果需要在路由层面统一处理,可以在GoRouter的路由配置中添加onExit回调:

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/webview',
      builder: (context, state) => WebViewPage(
        url: state.queryParameters['url']!,
      ),
      onExit: (context) async {
        final webPageState = context.findAncestorStateOfType<_WebViewPageState>();
        if (webPageState != null && await webPageState._webController.canGoBack()) {
          webPageState._webController.goBack();
          // 返回false阻止路由退出
          return false;
        }
        // 返回true允许路由退出
        return true;
      },
    ),
  ],
);

注意事项:

  • 需要确保能获取到WebViewController的实例,可通过GlobalKey或状态管理(如Provider)实现。
  • 该方案适合需要在路由全局层面控制返回行为的场景,灵活性不如页面内的PopScope。

内容的提问来源于stack exchange,提问作者Delmontee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 12:11:02