更改浏览器 Url Flutter 时无法导航到初始路由错误

Posted

技术标签:

【中文标题】更改浏览器 Url Flutter 时无法导航到初始路由错误【英文标题】:Could not navigate to initial route error when changing browser Url Flutter 【发布时间】:2022-01-04 09:43:02 【问题描述】:

我正在更新我的代码以使用 Navigator 2.0,并且通过 NavigationBar 的按钮进行导航可以正常切换页面并相应地更新浏览器 URL,当我手动更改它时会引发错误:

Could not navigate to initial route.
The requested route name was: "/retailers"
There was no corresponding route in the app, and therefore the initial route specified will be ignored and "/" will be used instead.

后退按钮也不起作用,并引发Duplicate GlobalKey detected in widget tree.error。 问题是我在解析器中检查routeInformation.location 吗?

编辑

我尝试将开关放在uri.pathSegment.lenght 中检查uri.pathSegments.first,现在后退按钮可以正常工作,但仍然抛出Duplicate GlobalKey detected in widget tree.错误。

if (uri.pathSegments.length > 0) 
      print(
          'Uri.segments.first is: $uri.pathSegments.first..uri.path is: $uri.path');
      // switch (routeInformation.location) 
      switch (uri.pathSegments.first) 
...

这是我的解析器:

class AppRouteInformationParser extends RouteInformationParser<RoutePath> 
  @override
  Future<RoutePath> parseRouteInformation(
      RouteInformation routeInformation) async 
    print(
        'AppRouteInformationParser.parseRouteInformation called for $routeInformation.location');
    final Uri uri = Uri.parse(routeInformation.location);
    if (uri.pathSegments.length > 0) 
      print(
          'Uri.segments.first is: $uri.pathSegments.first, uri.path is: $uri.path');
     else 
      print('AppRouteInformationParser uri has no segments and is $uri');
    

    switch (routeInformation.location) 
      // switch (uri.pathSegments.first) 
      case '/':
        print('AppRouteInformationParser.urlSegment switch case : /');
        // return CyclistsPath();
        return HomePath();
      case CyclistsLandingRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /cyclists');
        return CyclistsPath();
      case '/retailers':
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /retailers');
        return RetailersPath();
      case '/map':
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /map');
        return MapPath();
      case AboutRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /about');
        return AboutPath();
      case TermsOfServiceRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /terms-of-service');
        return TermsOfServicePath();
      case PrivacyPolicyRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /privacy-policy');
        return PrivacyPolicyPath();
      case PrivacySettingsRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /privacy-settings');
        return PrivacySettingsPath();
      case CommunityGuidelinesRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /community-guidelines');
        return CommunityGuidelinesPath();
      case LegalNoticeRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /legal-notice');
        return LegalPath();

      default:
        print(
            '### default AppRouteInformationParser.routeInformation.location switch case ## default: /');
        return HomePath();
    

  

  @override
  RouteInformation restoreRouteInformation(RoutePath path) 

    print(
        'AppRouteInformationParser.restoreRouteInformation called for path $path.selectedPath');

    switch (path.selectedPath) 
      case '/':
        // case CyclistsLandingRoute:
        print('restoreRouteInformation RouteInformation.location: /');
        return RouteInformation(location: '/');
      case '/cyclists':
        // case CyclistsLandingRoute:
        print('restoreRouteInformation RouteInformation.location: /cyclists');
        return RouteInformation(location: '/cyclists');

      case '/retailers':
        print('restoreRouteInformation RouteInformation.location: /retailers');
        return RouteInformation(location: '/retailers');
      case '/map':
        print('restoreRouteInformation RouteInformation.location: /map');
        return RouteInformation(location: '/map');
      case '/about':
        print('restoreRouteInformation RouteInformation.location: /about');
        return RouteInformation(location: '/about');
      case '/terms-of-service':
        print(
            'restoreRouteInformation RouteInformation.location: /terms-of-service');
        return RouteInformation(location: '/terms-of-service');
      case '/privacy-policy':
        print(
            'restoreRouteInformation RouteInformation.location: /privacy-policy');
        return RouteInformation(location: '/privacy-policy');
      case '/privacy-settings':
        print(
            'restoreRouteInformation RouteInformation.location: /privacy-settings');
        return RouteInformation(location: '/privacy-settings');
      case '/community-guidelines':
        print(
            'restoreRouteInformation RouteInformation.location: /community-guidelines');
        return RouteInformation(location: '/community-guidelines');
      case '/legal-notice':
        print(
            'restoreRouteInformation RouteInformation.location: /legal-notice');
        return RouteInformation(location: '/legal-notice');
      default:
        print(
            'restoreRouteInformation  ### Default RouteInformation.location: /cyclists');
        return RouteInformation(location: '/cyclists');
    
  

通过我设置的打印我还注意到,当应用第一次加载时可能会有一个奇怪的循环:

解析器

    AppRouteInformationParser.parseRouteInformation called for / AppRouteInformationParser uri has no segments and is / AppRouteInformationParser.urlSegment switch case : /

RuterDelegate

    RouterDelegate.currentConfiguration appState.selectedPage is

解析器

    AppRouteInformationParser.restoreRouteInformation called for path / restoreRouteInformation RouteInformation.location: /

路由器代理

    RouterDelegate.setNewRoutePath path is /

应用状态

    AppState setting selectedPage to / 这会触发委托构建,所以再次

路由器代理

    RouterDelegate.currentConfiguration appState.selectedPage is /

解析器

    AppRouteInformationParser.restoreRouteInformation called for path / restoreRouteInformation RouteInformation.location: /

非预期打印

路由器代理

    RouterDelegate.currentConfiguration appState.selectedPage is /

解析器

    AppRouteInformationParser.restoreRouteInformation called for path / restoreRouteInformation RouteInformation.location: /

当按下按钮时,我只会得到:

按钮

1.selected tapped is /about

应用状态

    AppState setting selectedPage to /about

路由器代理

    RouterDelegate.currentConfiguration appState.selectedPage is /about

解析器

    AppRouteInformationParser.restoreRouteInformation called for path /about restoreRouteInformation RouteInformation.location: /about

【问题讨论】:

【参考方案1】:

经过几天的努力,我终于找到了问题:

在 main.dart 构建方法中,我返回了 MaterialAppMaterialApp.router 作为其 home:,而不是直接返回 MaterialApp.router 并将所有 MaterialApp 配置参数移入其中。 现在一切正常。

错误的方式:

  AppRouterDelegate _routerDelegate = AppRouterDelegate();

  AppRouteInformationParser _routeInformationParser =
      AppRouteInformationParser();

  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: '',
      color: Colors.red,
      localizationsDelegates: [
        const AppLocalizationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('it', 'IT')
//        const Locale('es', 'ES'),
      ],
      localeResolutionCallback:
          (Locale locale, Iterable<Locale> supportedLocales) 
        for (Locale supportedLocale in supportedLocales) 
          if (supportedLocale.languageCode == locale.languageCode ||
              supportedLocale.countryCode == locale.countryCode) 
            print('Web device Locale is $locale');
            return supportedLocale;
          
        
        return supportedLocales.first;
      ,
      debugShowCheckedModeBanner: false,
      home: MaterialApp.router(
          routeInformationParser: _routeInformationParser,
          routerDelegate: _routerDelegate),
    );
  

正确的方法是:

AppRouterDelegate _routerDelegate = AppRouterDelegate();

  AppRouteInformationParser _routeInformationParser =
      AppRouteInformationParser();

  @override
  Widget build(BuildContext context) 
    return MaterialApp.router(
      routeInformationParser: _routeInformationParser,
      routerDelegate: _routerDelegate,
      debugShowCheckedModeBanner: false,
      title: '',
      color: Colors.red,
      localizationsDelegates: [
        const AppLocalizationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('it', 'IT')
//        const Locale('es', 'ES'),
      ],
      localeResolutionCallback:
          (Locale locale, Iterable<Locale> supportedLocales) 
        for (Locale supportedLocale in supportedLocales) 
          // if (UniversalPlatform.isWeb) 
          if (supportedLocale.languageCode == locale.languageCode ||
              supportedLocale.countryCode == locale.countryCode) 
            print('Web device Locale is $locale');
            return supportedLocale;
          
        
        return supportedLocales.first;
      ,
      // localeListResolutionCallback: ,
    );
  

【讨论】:

以上是关于更改浏览器 Url Flutter 时无法导航到初始路由错误的主要内容,如果未能解决你的问题,请参考以下文章

带有页面视图的自定义导航栏 [Flutter]

使用 Fluro 导航(Flutter web)

如何更改 Flutter web 中的 url?

Flutter - Provider 变量更改时触发导航

如何在颤动中将浏览器 URL 更新为非根导航器的路由更改?

导航上的 Vue url 更改