parseRouteInformationWithDependencies method

  1. @override
Future<RouteMatchList> parseRouteInformationWithDependencies(
  1. RouteInformation routeInformation,
  2. BuildContext context
)
override

Converts the given route information into parsed data to pass to a RouterDelegate.

The method should return a future which completes when the parsing is complete. The parsing may be asynchronous if, e.g., the parser needs to communicate with the OEM thread to obtain additional data about the route.

Consider using a SynchronousFuture if the result can be computed synchronously, so that the Router does not need to wait for the next microtask to pass the data to the RouterDelegate.

The input BuildContext can be used for looking up InheritedWidgets If one uses BuildContext.dependOnInheritedWidgetOfExactType, a dependency will be created. The Router will re-parse the RouteInformation from its RouteInformationProvider if the dependency notifies its listeners.

One can also use BuildContext.getElementForInheritedWidgetOfExactType to look up InheritedWidgets without creating dependencies.

Implementation

@override
Future<RouteMatchList> parseRouteInformationWithDependencies(
  RouteInformation routeInformation,
  BuildContext context,
) {
  // Normalize inputs into a RouteInformationState so we ALWAYS go through onEnter.
  final Object? raw = routeInformation.state;
  late final RouteInfoState infoState;
  late final Uri incomingUri;
  late final RouteInformation effectiveRoute;

  if (raw == null) {
    // Framework/browser provided no state — synthesize a standard "go" nav.
    // This happens on initial app load and some framework calls.
    infoState = RouteInformationState.go();
    incomingUri = routeInformation.uri;
  } else if (raw is! RouteInformationState) {
    // Restoration/back-forward: decode the stored match list and treat as restore.
    final RouteMatchList decoded = _routeMatchListCodec.decode(raw as Map<Object?, Object?>);
    infoState = RouteInformationState.restore(base: decoded);
    incomingUri = decoded.uri;
  } else {
    infoState = raw;
    incomingUri = routeInformation.uri;
  }

  // Normalize once so downstream steps can assume the URI is canonical.
  effectiveRoute = RouteInformation(
    uri: RouteConfiguration.normalizeUri(incomingUri),
    state: infoState,
  );

  // ALL navigation types now go through onEnter, and if allowed,
  // redirect() handles both top-level and route-level redirects.
  return _onEnterHandler.handleTopOnEnter(
    context: context,
    routeInformation: effectiveRoute,
    infoState: infoState,
    onCanEnter: () {
      final RouteMatchList initialMatches = configuration.findMatch(
        effectiveRoute.uri,
        extra: infoState.extra,
      );
      return _navigate(effectiveRoute, context, infoState, startingMatches: initialMatches);
    },
    onCanNotEnter: () {
      // If blocked, stay on the current route by restoring the last known good configuration.
      if (router.routerDelegate.currentConfiguration.isNotEmpty) {
        return SynchronousFuture<RouteMatchList>(router.routerDelegate.currentConfiguration);
      }

      if (_lastMatchList != null) {
        return SynchronousFuture<RouteMatchList>(_lastMatchList!);
      }

      // No prior route to restore (e.g., an initial deeplink was blocked).
      // Surface an error so the app decides how to recover via onException.
      final RouteMatchList blocked = _OnEnterHandler._errorRouteMatchList(
        effectiveRoute.uri,
        BlockedInitialNavigationException(
          'Navigation to ${effectiveRoute.uri} was blocked by onEnter with no prior route to restore',
        ),
        extra: infoState.extra,
      );
      final RouteMatchList resolved = onParserException != null
          ? onParserException!(context, blocked)
          : blocked;
      return SynchronousFuture<RouteMatchList>(resolved);
    },
  );
}