Learn

How a navigation request reaches Flutter

See the five objects in a working request, where each one is created, and which object your feature code actually uses.

v1.1.0Beginner

How a navigation request reaches Flutter

Consider a catalog page that opens Product and expects a purchase result:

dart
final NavigationTicket<bool> ticket = context.readNavigation.push<bool>(
  const ProductDestination('keyboard-42'),
);

Five objects take part. Only the first and last normally appear in feature UI code.

ObjectWhat it doesWhere you create it
ProductDestinationCarries typed intent and parametersFeature/domain-facing code
productRouteBuilds ProductPage and maps the Destination to a URIFeature navigation module
NavigationGraphCombines routes, modules, scopes, and policiesApplication startup code
NavigationSessionOwns the mutable stacks and Flutter Router objectsRoot StatefulWidget
NavigationPortExposes exact operations to application codeRead from context or inject as an interface

The request path

For the call above, Ark Navigation:

  1. finds the Route Definition that accepts ProductDestination;
  2. selects its Module, Mount, and Navigator Scope;
  3. applies Redirects;
  4. checks leave and enter Guards;
  5. commits one new immutable Snapshot;
  6. asks Flutter Router to render the new page;
  7. completes ticket.committed;
  8. later completes ticket.completed when Product is popped or removed.

No page is inserted before policy checks finish.

The owner you must not forget

Create one Session for one Flutter view and dispose it with that view:

dart
final class AppHostState extends State<AppHost> {
  late final NavigationSession navigation = NavigationSession(
    id: const NavigationSessionId('main-window'),
    graph: createAppGraph(),
  );

  @override
  Widget build(BuildContext context) => MaterialApp.router(
    routerConfig: navigation.routerConfig,
  );

  @override
  void dispose() {
    navigation.dispose();
    super.dispose();
  }
}

Do not create the Session in build(). That would replace Navigator keys, browser-history state, stacks, and pending result tickets on a rebuild.

What feature code should depend on

In a widget callback:

dart
context.readNavigation.push<void>(const SettingsDestination());

In a Presenter or application service, accept NavigationPort through the constructor. Do not store BuildContext there:

dart
final class CheckoutPresenter {
  CheckoutPresenter(this.navigation);
  final NavigationPort navigation;

  void showReceipt(String orderId) {
    navigation.replaceTop<void>(ReceiptDestination(orderId));
  }
}

Use NavigationController only for infrastructure tasks such as restoration or Graph updates. Regular features need the smaller NavigationPort.