auto_route 0.6.1

  • Readme
  • Changelog
  • Example
  • Installing
  • 98

auto_route: #

AutoRoute is a declarative routing solution, where everything needed for navigation is automatically generated for you.


Installation #

dependencies:
  auto_route: [latest-version]

dev_dependencies:
  auto_route_generator: [latest-version]
  build_runner:

Setup and Usage #


First create a router class and annotate it with @MaterialAutoRouter, @CupertinoAutoRouter, @AdaptiveAutoRouter or @CustomAutoRoute. It's name must be prefixed with $ to get a generated class with the same name minus the $. $Router => Router

Note: using $ prefix is mandatory.
@MaterialAutoRouter(...config)  //CustomAutoRoute(..config)
class $Router {}

Declare your AutoRoutes in MaterialAutoRouter() annotation

@MaterialAutoRouter(
  routes: <AutoRoute>[
    // initial route is named "/"
    MaterialRoute(page: HomeScreen, initial: true),
    MaterialRoute(page: UsersScreen, ..config),
  ],
)
class $Router {}

Now simply run the generator

Use the [watch] flag to watch the files system for edits and rebuild as necessary.

flutter packages pub run build_runner watch

if you want the generator to run one time and exits use

flutter packages pub run build_runner build

Finalize the setup

after you run the generator your router class will be generated


    MaterialApp(
    // Let MaterialApp use ExtendedNavigator instead of
    // the native one by assigning it to it's builder
     builder: ExtendedNavigator<Router>(router: Router()),

     // ExtendedNavigator is just a widget so you can still wrap it
     // with other widgets if you need to
     builder: (ctx, nativeNavigator) => Theme(
       data:...,
       child: ExtendedNavigator<Router>(router: Router())
     ,)
    );

Using the native navigator #

Note Without ExtendedNavigator you will lose support for RouteGuards and auto-nested navigation handling.

     MaterialApp(
      // assign your generated Router directly to onGenerateRoute property
        onGenerateRoute: Router()
    );

Inside of the generated file

// a Routes class that holds all of your static route names
class Routes {
  static const String homeScreen = '/';
  static const String usersScreen = '/users-screen';
  static const all = <String>{
    homeScreen,
    usersScreen,
  };
}

class Router extends RouterBase {
  @override
  List<RouteDef> get routes => _routes;
  final _routes = <RouteDef>[
    RouteDef(Routes.homeScreen, page: HomeScreen),
    RouteDef(Routes.usersScreen, page: UsersScreen),
  ];
  @override
  Map<Type, AutoRouteFactory> get pagesMap => _pagesMap;
  final _pagesMap = <Type, AutoRouteFactory>{
    HomeScreen: (RouteData data) {
      return MaterialPageRoute<dynamic>(
        builder: (context) => HomeScreen(),
        settings: data,
      );
    },
    ...
 // Argument holder classes if exist ...

Customizing routes #


There are several available auto-route types which you can customize

  • MaterialRoute -> will generate a MaterialRoutePage
  • CupertinoRoute -> will generate a CupertinoRoutePage
  • AdaptiveRoute -> will generate Cupertino or Material route page based on the Platform
  • CustomRoute -> will generate a PageRouteBuilder with the provided Customizations
@MaterialAutoRouter(
  routes: <AutoRoute>[
    MaterialRoute(page: HomeScreen, initial: true, name: "InitialRoute"),
    CupertinoRoute(page: UsersScreen, fullscreenDialog: true),
    //This route returns result of type [bool]
    CustomRoute<bool>(page: LoginScreen, transitionsBuilder: TransitionsBuilders.fadeIn),
  ],
)
class $Router {}

Custom path names

AutoRoute automatically generates paths based on page type, for example the generated path for HomeScreen is "/home-screen". You probably won't need to customize your paths unless your are building a web application. To use a custom path name use the path property inside of AutoRoute

MaterialRoute(path: "/users", page: UsersScreen)

Available customizations

MaterialAutoRouter | CupertinoAutoRouter | AdaptiveAutoRouter
PropertyDefault valueDefinition
generateNavigationHelperExtension [bool]falseif true a Navigator extension will be generated with helper push methods of all routes
routePrefix [String]''all route paths will be prefixed with this routePrefix String
routesClassName [string]'Routes'the name of the generated Routes class

CustomAutoRouter

PropertyDefault valueDefinition
transitionsBuildernullextension for the transitionsBuilder property in PageRouteBuilder
opaquetrueextension for the opaque property in PageRouteBuilder
barrierDismissiblefalseextension for the barrierDismissible property in PageRouteBuilder
durationInMillisecondsnullextension for the transitionDuration(millieSeconds) property in PageRouteBuilder

MaterialRoute | CupertinoRoute | AdaptiveRoute | CustomRoute

PropertyDefault valueDefinition
initialfalsemark the route as initial '\'
pathnullan auto generated path will be used if not provided
namenullthis will be assigned to the route variable name if provided and it will be used to name the route's nested Router if it has one (String homeScreen = [name]);
fullscreenDialogfalseextension for the fullscreenDialog property in PageRoute
maintainStatetrueextension for the maintainState property in PageRoute

CupertinoRoute Specific => CupertinoPageRoute

PropertyDefault valueDefinition
titlenullextension for the title property in CupertinoPageRoute

CustomRoute Specific => PageRouteBuilder

PropertyDefault valueDefinition
transitionsBuildernullextension for the transitionsBuilder property in PageRouteBuilder
opaquetrueextension for the opaque property in PageRouteBuilder
barrierDismissiblefalseextension for the barrierDismissible property in PageRouteBuilder
durationInMillisecondsnullextension for the transitionDuration(millieSeconds) property in PageRouteBuilder

Passing arguments to routes #


That's the fun part!

You don't actually need to do anything extra. AutoRoute automatically detects your route parameters and handles them for you, it will automatically generate a class that holds your screen arguments and keep them typed.

class WelcomeScreen extends StatelessWidget {
  final String title;
  final String message;
  const WelcomeScreen({this.title = "Default Title",@required this.message});

  @override
  Widget build(BuildContext context)...
}

Generated arguments holder for the above example

  • Default values are respected.
  • Required fields are also respected and handled properly.
class WelcomeScreenArguments {
  final String title;
  final String message;
  // you're not going to lose your default values;
  WelcomeScreenArguments({this.title = "Default Title",@required this.message});
}
Pass your typed args using the generated arguments holder class
ExtendedNavigator.of(ctx).pushNamed(Router.welcomeScreenRoute,
    arguments: WelcomeScreenArguments(
        title: "Hello World!"
        message: "Let's AutoRoute!"
        )
    );

Dynamic routing aka path parameters #


requires AutoRoute: >= 0.6.0 Define a dynamic segment by prefixing it with a colon

MaterialRoute(path: "/users/:id", page: UsersScreen);

Now pushing users/1 will match /users:id and the path parameter id will be extracted and exposed in RouteData

Extracting route parameters #


Extracted path parameters & queryParameters are bundled inside of an object called RouteData which you can get by calling RouteData.of(context) inside of the current route page.

class UsersScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   var routeData = RouteData.of(context)
    // .value will return the raw string value
     var userId = routeData.pathParams['id'].value;
     // .intValue will return a parsed int or null if parsing fails
   int userId = routeData.pathParams['id'].intValue;
   var queryParams = routeData.queryParams;
     ...

isn't there a better way to extract route parameters? This doesn't feel very auto! #

of course there is! simply annotate your constructor parameters with @PathParam() or @QueryParam() and let auto_route do the work for you

class UsersScreen extends StatefulWidget {
  const UsersScreen({
    @PathParam() this.id,
    // if your var name is different from the param name you
    // can pass it's expected name to the annotation
    // e.g [/users/1?filter=testers]
    @QueryParam('filter') this.filterFromQuery,
  });

Generated code for UsersScreen

  MaterialPageRoute<dynamic>(
       builder: (context,) => UsersScreen(
       // auto_route will know the right type to parse the raw value to
       id: data.pathParams['id'].intValue,
       filterFromQuery: data.queryParams['filter'].stringValue)

Note constructor parameters annotated with @PathParam() or @QueryParam will not be considered as argument parameters and will be excluded from the generated argument class holder

Handling unknown routes #


requires AutoRoute: >= 0.6.0

Using a wildcard

AutoRoute 0.6.0 supports wildcard matching, you can simply declare a wildcard at the end of your routes list to catch any undefined routes.

@MaterialAutoRouter(
  routes: <AutoRoute>[
    MaterialRoute(page: HomeScreen, initial: true),
    MaterialRoute(page: UsersScreen),
    // This should be at the end of your routes list
    // wildcards are represented by '*'
    MaterialRoute(path: "*", page: UnknownRouteScreen)
  ],
)
class $Router {}

Using the onUnknownRoute callback function in ExtendedNavigator

This function is called when the matcher fails to find a route to return, a default error page is returned if onUnknownRoute is not provided

ExtendedNavigator(
    router: Router(),
    onUnknownRoute:(RouteSettings settings){
        // return your Error page
    } ,
   ...

Nested Routes #


Declaring your nested routes inside of the parent route's children property will generate a nested router class called UsersScreenRouter, if you provide a custom name for the parent route the nested router name will be customName+Router

@MaterialAutoRouter(
  routes: <AutoRoute>[
    MaterialRoute(page: HomeScreen, initial: true),
    MaterialRoute(
      path: '/users:id',
      page: UsersScreen,
      children: <AutoRoute>[
        // path: '/' is the same as setting initial to true
        MaterialRoute(path: '/', page: ProfileScreen),
        MaterialRoute(path: '/posts', page: PostsScreen),
      ],
    ),
  ],
)
class $Router {}

Now we need to render these nested routes inside of their parent UsersScreen and for that we use a NestedNavigator(), this widget will build an ExtendedNavigator and provide it with the right router. this is the same as using <router-outlet> in Angular or <router-view> in Vue.

class UsersScreen extends StatelessWidget {
  ...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Users Page")),
      // this navigator will obtain it's router
      // on it's own
      body: NestedNavigator(),
    );
  }
}

You can either use context to look up your Navigator in your widgets tree or without context, by router or name.

with context

ExtendedNavigator.of(context).pushNamed(..)

by Router

ExtendedNavigator.ofRouter<Router>().pushNamed(..)

by Name -> requires AutoRoute: >= 0.6.0

// give your navigator a name
ExtendedNavigator(router: Router(), name: "root")
NestedNavigator(name: "nestedNav")
//call it by it's name
ExtendedNavigator.byName("nestedNav").pushNamed(..)

if you're working with only one navigator

ExtendedNavigator.root.pushNamed(..)

to generate extension methods set the generateNavigationHelperExtension property inside of MaterialAutoRouter() to true

This will generate

extension RouterNavigationHelperMethods on ExtendedNavigatorState {
  Future pushHomeScreen() => pushNamed(Routes.homeScreen);
  Future<bool> pushSecondScreen(
          {@required String title, String message}) =>
      pushNamed<bool>(Routes.secondScreen,
          arguments: SecondScreenArguments(title: title, message: message));
}

Then use it like follows

ExtendedNavigator.of(context).pushSecondScreen(args...);
//or
ExtendedNavigator.ofRouter<Router>().pushSecondScreen(args...)

Route guards #


Implementing route guards requires a little bit of setup:

  1. Create your route guard by extending RouteGuard from the autoRoute package
class AuthGuard extends RouteGuard {
 @override
 Future<bool> canNavigate(
     ExtendedNavigatorState navigator, String routeName, Object arguments) async {

   SharedPreferences prefs = await SharedPreferences.getInstance();
   return prefs.getString('token_key') != null;
 }
}
  1. Register the guards inside of ExtendedNavigator
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: ExtendedNavigator<Router>(
        router: Router(),
        guards: [AuthGuard()],
      ),
    );
  }
}

Finally assign the guards to the route you want to protect

 MaterialRoute(page: ProfileScreen, guards: [AuthGuard])

Handling Wrapped Routes #


To wrap your route with a parent widget like a Provider or such, simply implement AutoRouteWrapper, and let wrappedRoute(context) method return (this) as the child of your wrapper widget.

class ProductsScreen extends StatelessWidget implements AutoRouteWrapper {
  @override
  Widget wrappedRoute(BuildContext context) {
  return Provider(create: (ctx) => ProductsBloc(), child: this);
  ...

Custom Route Transitions #


To use custom Transitions use the @CustomRoute() annotation and pass in your preferences. The TransitionsBuilder function needs to be passed as a static/const reference that has the same signature as the TransitionsBuilder Function of the PageRouteBuilder class. The included TransitionsBuilders Class contains a preset of common Transitions builders

@CustomRoute(transitionsBuilder: TransitionBuilders.slideBottom,durationInMilliseconds: 400)
LoginScreen loginScreenRoute;

Use @CustomAutoRouter() to define global custom route Transitions.

You can of course use your own transitionsBuilder function as long as it has the same function signature. The function has to take in exactly a BuildContext, Animation[Double], Animation[Double] and a child Widget and it needs to return a Widget, typically you would wrap your child with one of flutter's transition Widgets as follows.

Widget zoomInTransition(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
 // you get an animation object and a widget
 // make your own transition
    return ScaleTransition(scale: animation, child: child);
  }

Now pass the reference of your function to CustomRoute() .

CustomRoute(page: ZoomInScreen, transitionsBuilder: zoomInTransition)

Migration guide #


I apologize for the good 5 to 10 minutes you're gonna lose rewriting your router class but it's for the greater good ;).

Migrating from auto_route <= 0.5.0

Basically instead of declaring our routes as class fields we're going to use a more readable and scalable way (a static routes list).

old way <= 0.5.0

@MaterialAutoRouter()
class $Router{
    @initial
    HomeScreen homeScreen;
}

new way >= 0.6.0

@MaterialAutoRouter(
routes:[
  MaterialRoute(page: HomeScreen, initial: true),
]
)
class $Router{}
Route Customization

old way <= 0.5.0

@MaterialAutoRouter()
class $Router{
    @CupertinoRoute(fullscreenDialog: true, returnType: bool)
    LoginScreen loginScreen;

    @CustomRoute(transitionBuilder: TransitionsBuilders.fadeIn)
    ProfileScreen profileScreen;
}

new way >= 0.6.0

@MaterialAutoRouter(
routes:[
  CupertinoRoute<bool>(page: LoginScreen, fullscreenDialog: true),
  CustomRoute(page: ProfileScreen, transitionBuilder: TransitionsBuilders.fadeIn)
 ],
)
class $Router{}
Route Guards

old way <= 0.5.0

@MaterialAutoRouter()
class $Router{
    @GuardedBy[AuthGuard]
    ProfileScreen profileScreen;
}

new way >= 0.6.0

@MaterialAutoRouter(
routes:[
  MaterialRoute(page: ProfileScreen, guards:[AuthGuard]),
 ],
)
class $Router{}
Custom UnknownRoute screen

old way <= 0.5.0

@MaterialAutoRouter()
class $Router{
    @unknownRoute
    UnknownRouteScreen unknownRoute;
}

new way >= 0.6.0

@MaterialAutoRouter(
routes:[
  ...
  // order is important here, this must be at the end of your routes list
  MaterialRoute(path: '*', page: UnknownRouteScreen),
 ],
)
class $Router{}

Problems with the generation? #


Make sure you always Save your files before running the generator, if that doesn't work you can always try to clean and rebuild.

flutter packages pub run build_runner clean

Support auto_route #

You can support auto_route by liking it on Pub and staring it on Github, sharing ideas on how we can enhance a certain functionality or by reporting any problems you encounter

ChangeLog #

[0.6.1] #

  • Fix pop until name issue by implementing PopUntilPath and RouteData.withPath
  • Fix opening deep links in new tabs pushes initial route only

[0.6.0+1] #

  • Fix README file linkes

[0.6.0] Breaking Change #

  • Change the way routes are declared from class fields to a static list
  • Add support for path & query parameters
  • Add support for path wildcards
  • Add support for nested routes
  • Add support for generic result types
  • Add get ExtendedNavigator by name feature
  • Merge fix for adaptive route web support issue
  • Change generating arguments holder for single parameter routes is not optional anymore
  • Minor fixes and enhancements

[0.5.0] #

  • Add allRoutes getter to RouterBase
  • minor fixes

[0.4.6] Skip #

[0.4.5] Breaking Change #

  • Add AdaptiveAutoRouter and AdaptiveRoute for native platforms
  • Change using leading slashes is now options
  • Change wrappedRoute is now a function that takes in build context
  • Fix calling nested route returns null after popping parent route
  • Fix initial route ignore custom transitions
  • Add ability to name routes class

[0.4.4] #

  • Change generating arguments holder for single parameter routes is not optional
  • Fix android soft back button always pops root navigator

[0.4.3] Breaking Changes #

  • Add ability to pass initial route arguments to ExtendedNavigator
  • Change single route parameters will have argument holder classes too as requested
  • Fix ExtendedNavigator.ofRouter

[0.4.2] #

  • Fix Android soft back button always exists App

[0.4.1] Breaking Changes #

  • Fix isInitialRoute not defined for RouteSettings in flutter 1.15.+

[0.4.0] Breaking Changes #

  • Change using ExtendedNavigator instead of the native Navigator
  • Fix initial route does not go through guards
  • Change generated router class is no longer static
  • Change routes are generated in their own class now "Routers"
  • Add option to generate navigation helper methods extension
  • Update README file

[0.3.1] #

  • Fix Compilation Fails in flutter 1.15.+
  • Fix third party imports src instead of library
  • Fix guardedRoutes is generated even if it's empty
  • Add support for custom unknown route screen

[0.3.0] Breaking Changes! #

  • Add global route customization Use MaterialAutoRouter, CupertinoAutoRouter or CustomAutoRouter instead of AutoRouter
  • Navigator key is now accessed by calling Router.navigator.key instead of Router.navigatorKey.
  • Add Route guards
  • Add optional returnType param in all AutoRoute types.
  • Remove generate Navigator Key optional.
  • Fix generate error when using dynamic vars in route widget constructors

[0.2.2] #

  • Add option to generate a list with all route names
  • change generating navigator key is now optional
  • Fix prevent importing system library files
  • Change generated route path name are now Kabab cased (url-friendly)
  • Add ability to use custom path names in all route types
  • Update README file

[0.2.1] #

  • add Route Wrapper
  • add initial flag as a property in all route types
  • change prefix const route names with class name.
  • add fullscreenDialog property to @CustomRoute()

[0.2.0+1] #

  • format README file

[0.2.0] #

Breaking Changes! #

  • change to using a single config file instead of annotating the actual widget class due to performance issues.
  • add @MaterialRoute(), @CupertinoRoute() and @CustomRoute() annotations
  • remove @AutoRoute() annotation and add @AutoRouter()
  • handle required parameters.
  • add navigating with a global navigator key [without context].
  • support nested navigators.

[0.1.1] #

  • code formatting.

[0.1.0] #

  • initial release.

example/README.md


class HomeScreen extends StatelessWidget{}

class LoginScreen extends StatelessWidget {}

@MaterialAutoRouter(
  routes: <AutoRoute>[
    MaterialRoute(page: HomeScreen, initial: true),
    MaterialRoute( page: LoginScreen, fullscreenDialog: true),
  ],
)
class $Router {}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  auto_route: ^0.6.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:auto_route/auto_route.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
96
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
98
Learn more about scoring.

We analyzed this package on Jul 11, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.14
  • Flutter: 1.17.5

Analysis suggestions

Package not compatible with SDK dart

Because:

  • auto_route that is a package requiring null.

Package not compatible with runtime flutter-web on web

Because:

  • package:auto_route/auto_route.dart that imports:
  • package:auto_route/src/router_utils.dart that imports:
  • dart:io

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.5.0 <3.0.0
flutter 0.0.0
meta ^1.1.8 1.1.8 1.2.2
Transitive dependencies
collection 1.14.12 1.14.13
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety