safe_route

pub.flutter-io.cn

safe_route is a simple and type-safe navigation helper for Flutter applications.
No more dynamic arguments and runtime crashes — everything is strictly typed.


Why?

Default Flutter navigation with Navigator.pushNamed requires Object? arguments.
It’s flexible but unsafe:

Navigator.of(context).pushNamed('/user', arguments: 123); // ❌ runtime crash if page expects String

With safe_route, both arguments and results are typed at compile-time.


Features

  • ✅ Type-safe arguments and results
  • ✅ Nested routes (SafeNestedRoute)
  • ✅ Strongly typed navigation helpers
  • ✅ Clean, declarative API
  • ✅ Simple integration with MaterialApp

Installation

Add to pubspec.yaml:

dependencies:
  safe_route: ^<latest_version>

Quick Start

1. Define routes

final homeRoute = SafeRoute<Null, int>(
  name: '/',
  builder: (context, _) => const HomePage(),
);

final settingsRoute = SafeRoute<int, bool>(
  name: '/settings',
  builder: (context, arguments) => const SettingsPage(),
);

2. Register them in SafeRouter

final router = SafeRouter()
  ..registerAll([homeRoute, settingsRoute])
  ..defaultPath = homeRoute.fullPath;

MaterialApp(
  initialRoute: router.defaultPath,
  onGenerateRoute: router.onGenerateRoute,
);

3. Navigate safely

// Navigate without arguments
Navigator.of(context).pushRoute(homeRoute, null);

// Navigate with arguments
Navigator.of(context).pushRoute(userRoute, "Alex");

// Return a result
Navigator.of(context).popRoute(userRoute, true);

// Receive a result
final isDark = await Navigator.of(context).pushRoute(settingsRoute, null);

safe_route provides a convenient extension AppRouteNavigation on NavigatorState with typed wrappers around standard navigation methods:

Flutter API method safe_route method
pushNamed pushRoute
maybePop maybePopRoute
pop popRoute.
popAndPushNamed popAndPushRoute
pushNamedAndRemoveUntil pushRouteAndRemoveUntil
pushReplacementNamed pushReplacementRoute
restorablePushNamed restorablePushRoute
restorablePopAndPushNamed restorablePopAndPushRoute
restorablePushNamedAndRemoveUntil restorablePushRouteAndRemoveUntil
restorablePushReplacementNamed restorablePushReplacementRoute

All methods ensure arguments and results are strictly typed.


Full Example


class AppRouter {
  AppRouter() : safeRouter = SafeRouter() {
    safeRouter
      ..registerAll([
        loginRoute,
        homeRoute,
        settingsRoute,
      ])
      ..defaultPath = homeRoute.fullPath;
  }

  final SafeRouter safeRouter;

  

  final loginRoute = SafeRoute<Null, String>(
    name: '/',
    builder: (context, __) => const LoginPage(),
  );

  final homeRoute = SafeRoute<String, void>(
    name: '/home',
    builder: (context, username) => HomePage(username: username),
  );

  final settingsRoute = SafeRoute<Null, bool>(
    name: '/settings',
    builder: (context, __) => const SettingsPage(),
  );
}

final AppRouter router = AppRouter();

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: router.safeRouter.defaultPath,
      onGenerateRoute: router.safeRouter.onGenerateRoute,
    );
  }
}