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

Could not navigate to initial route error when changing browser Url Flutter

我正在更新我的代码以使用 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. 错误。 问题是我在解析器中检查了 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');
    }
  }
}

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

解析器

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

RuterDelegate

  1. RouterDelegate.currentConfiguration appState.selectedPage is

解析器

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

路由器代理

  1. RouterDelegate.setNewRoutePath path is /

应用状态

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

路由器代理

  1. RouterDelegate.currentConfiguration appState.selectedPage is /

解析器

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

非预期打印

路由器代理

  1. RouterDelegate.currentConfiguration appState.selectedPage is /

解析器

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

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

按钮

1.selected tapped is /about

应用状态

  1. AppState setting selectedPage to /about

路由器代理

  1. RouterDelegate.currentConfiguration appState.selectedPage is /about

解析器

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

折腾了几天终于找到问题所在:

在 main.dart 构建方法中,我返回一个 MaterialApp,其中 MaterialApp.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: ,
    );
  }