Development
-
March 13, 2023

Flutter Navigation with Router Go

Flutter navigation allows you to navigate from one widget to another in your app. This function is achieved using a navigation stack, a collection of routes.

Navigator is a built-in Flutter widget that provides a simple and convenient way to manage the navigation stack and navigate between routes. It's straightforward to use and can be a good choice for basic navigation needs. 

On it, a route represents a widget and its associated data. When you navigate to a new route, it is pushed onto the navigation stack, and when you navigate back, the current route is popped off the stack.

Navigator provides several navigation widgets, including Navigator, MaterialPageRoute, and CupertinoPageRoute, that make it easy to manage the navigation stack and provide common navigation patterns.

With Navigator, you can push and pop routes and manage the navigation stack. MaterialPageRoute and CupertinoPageRoute are two common Flutter routes used to transition between pages. They provide animation and visual effects appropriate for the material design or Cupertino design languages, respectively.

Flutter Navigation Disadvantages

Overall, Flutter navigation is designed to be flexible, allowing you to create complex navigation patterns that meet the needs of your app. But there are some limitations and potential problems that you should be aware of:

Limited routing features

Navigator provides basic routing functionality but only offers advanced features like named routes, path parameters, query parameters, or wildcard matching, making building more complex navigation patterns challenging.

Code complexity

As your app grows in complexity, managing the navigation stack with Navigator can become more challenging, making your code more difficult to maintain and debug.

Lack of customizability

Navigator provides basic animation and visual effects for transitioning between routes but does need to customize the routing transitions and animations.

Global state management

Navigator doesn't offer a built-in solution for managing the global states, making it challenging to share data between routes.

Inconsistent navigation patterns

Because Navigator is a low-level widget, ensuring that navigation patterns are consistent across your app can be challenging and lead to a fragmented user experience.

These limitations can make building complex, scalable, and consistent navigation patterns with Navigator challenging. If you encounter these limitations, consider using a third-party routing library such as go_router to address them.

On the other hand, go_router is a third-party routing library maintained by the Flutter team that provides advanced routing functionality unavailable in Navigator.

Flutter application developing code

For example, go_router delivers features such as named routes, path parameters, query parameters, and wildcard matching, which can be useful for building more complex navigation patterns.

Additionally, go_router provides a more elegant and declarative approach to routing, making it easier to manage the routing logic in your app. This can help to make your code more organized and maintainable, especially as your app grows in complexity.

If you need advanced routing features and a more elegant routing solution, you may consider using go_router. But if your navigation needs are simple, Navigator may be a more appropriate option.

Go_router Advantages

There are several advantages of using go_router in Flutter. Let’s take a look. 

Named routes

Go_router supports named routes, which makes it easier to manage and organize the navigation logic in your app. Named routes allow you to define the routes in a central location and then reference them throughout your app, making it easier to change your navigation logic in the future.

Path parameters

Go_router supports path parameters, which allow you to pass data to your routes based on the URL. This is useful for building dynamic navigation patterns, such as when passing an ID or other data to a route.

Query parameters

Go_router also supports query parameters, which allow you to pass data to your routes through the URL query string. This is useful for cases where you must pass data not part of the route path.

Wildcard matching

Go_router supports wildcard matching, which makes it easy to define catch-all routes that can handle any URL that doesn't match another route.

Declarative routing

Go_router provides a more elegant and declarative approach to routing, making it easier to manage the routing logic in your app. This can help to make your code more organized and maintainable, especially as your app grows in complexity.

Custom routing transitions 

Go_router allows you to customize the routing transitions and animations, making it possible to create custom and unique navigation experiences in your app.

Overall, go_router provides several advanced routing features that make it easier to manage and organize the navigation logic in your Flutter app. If your navigation needs are complex, go_router may be a good choice for your project.

Let's see an example of how we can structure our app:

Custom routing transitions

CODE: https://gist.github.com/amaury901130/60814b289fcacdf83c52c862a5ea002a.js

Go_router manages different types of routes:

  • ShellRoute - a container; basically, all the child routes will be rendered inside of its widget.
  • i.e. - HomeCorePage can have a container that renders a child widget with a classic nav drawer or a bottom nav bar to navigate between screens. As usual, when you change between screens, HomeCorePage again renders the new child and keeps the state of the rest of the screen.

CODE: https://gist.github.com/amaury901130/fd6db73ecbd598f376545b3c63c963b9.js

  • GoRoute: the main route type; this is where you declare your route with the widget to render and can have different children. Let's see:

CODE: https://gist.github.com/amaury901130/cd4b69c500310a9ed17333ba3ef7d33c.js

Here we can see different things:

  • Every route can have N sub-routes.
  • We can add validations before navigating to a sub-route and redirect the user to any other page we need if it doesn't match the validation.

Another advantage of go_router is that we can manage nav errors easily in the GoRouter class:

CODE: https://gist.github.com/amaury901130/4268ec08182d6c326c66579700fb903f.js

Deeplinks

When a deep link is received from the platform, GoRouter will display the configured screen based on the URL path. See the deep linking documentation at Flutter to configure your Android or iOS app for deep linking.dev:

Enable deep linking on Android

Add a metadata tag and intent filter to AndroidManifest.xml inside the <activity> tag with the ".MainActivity" name:

CODE: https://gist.github.com/amaury901130/3622f2a6bdfb600fbacc0dff44f19299.js

A full restart is required to apply these changes.

Test on Android emulator

To test with an Android emulator, give the adb command an intent where the hostname matches the name defined in AndroidManifest.xml:

adb shell 'am start -a android.intent.action.VIEW \\ -c android.intent.category.BROWSABLE \\ -d "<http://flutterbooksample.com/book/1>"' \\ <package name>

Replace the <package name> with the package name of your Android app. If you named the package com.example.myflutterapp, run the following command:

adb shell 'am start -a android.intent.action.VIEW \\ -c android.intent.category.BROWSABLE \\ -d "<http://flutterbooksample.com/book/1>"' \\ com.example.myflutterapp

For more details, please look at the Verify Android App Links documentation in the Android docs.

Enable deep linking on iOS

Add two new keys to Info.plist in the ios/Runner directory:

CODE: https://gist.github.com/amaury901130/74c43f74928a0850ebe3e5401d22087d.js

The CFBundleURLName is a unique URL that distinguishes your app from others that use the same scheme. The scheme (customscheme://) can also be unique.

A full restart is required to apply these changes.

Test on iOS simulator

Use the xcrun command to test on the iOS Simulator:

xcrun simctl openurl booted customscheme://flutterbooksample.com/book/1

Final Thoughts

Go_router is an alternative to Navigator that offers some advantages over the latter, especially in large and complex applications.

We strongly recommend that if you're working on a complex application and need advanced navigation management, you should consider using go_router. 

Below are some reasons why we should consider using go_router instead of Navigator:

Greater flexibility in defining routes

Go_router allows for a more flexible definition of navigation routes than Navigator. With go_router, we can define routes based on criteria, such as the access route, URL parameters, application state, etc.

Better navigation management

Go_router offers more advanced navigation management than Navigator. For example, go_router allows us to define multiple navigation stacks for different areas of the application, making it easier to navigate between them without losing context.

Integration with the BLoC pattern

Go_router integrates well with the Business Logic Component (BLoC) pattern, a popular architecture pattern in Flutter. Go_router allows us to define routes directly linked to BLoC events, making managing navigation and application state easier.

Better performance

Go_router offers performance improvements over Navigator in large and complex applications. Go_router uses a tree-based data structure to store navigation routes, allowing for faster and more efficient route lookup.

What do you think about these two options? Do you agree that Go-router is a better alternative to Flutter Navigator? Let us know in the comments section.