Flutter Navigator 2.0 and Deep Links

With Flutter’s Navigator 2.0, learn how to handle deep links in Flutter and gain the ultimate navigation control for your app. By Kevin D Moore.

3.9 (26) · 3 Reviews

Download materials
Save for later
Share

Flutter’s first stable release was in December 2018, and it has grown rapidly since then. As is the case with any software, the developers who built it or use it are constantly refining it with each new version.

Initially, navigation between pages in Flutter was possible with Navigator 1.0 only, which could push and pop pages. Most use cases required basic navigation that wasn’t a problem for Navigator 1.0. But with the introduction of more complex navigation use cases — especially after Flutter for Web came out — developers wanted the ability to add multiple pages in one go or remove any offscreen page(s) on the onscreen page. To cover these use cases, the Flutter team introduced Navigator 2.0.

Note: In Flutter, screens and pages are called routes. However, in this tutorial you will mostly see screens or pages, and routes a few times. They mean the same thing for the most part.

In this tutorial, you’ll learn how to use Navigator 2.0 by building pages of a shopping app brilliantly called, Navigation App :]. You’ll also learn how it can provide much more granular control for your app’s navigation and deep linking. To do so, you’ll learn how to implement:

  • RouterDelegate
  • RouteInformationParser
  • BackButtonDispatcher

This tutorial uses Android Studio, but Visual Studio Code or IntelliJ IDEA will work fine as well.

Note: Navigator 2.0 is backward-compatible, and if needed, you can gradually introduce it to your existing apps that use Navigator 1.0 — without introducing any breaking changes.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the page.

The starter app is a set of screens for the shopping app. The UI doesn’t do much, but it shows how to navigate between pages. This set of pages — represented as screens — is in the image below:

The app starts with the Splash page, which shows an image:

Splash Page with image

Run your app and verify it opens to this page. The app will stay on this page since the navigation system isn’t yet implemented. Gradually, you’ll add code to navigate between all screens.

Once you implement the navigation, the app should display the Splash page for a short duration and then show the Login page if the user isn’t logged in. If they are, they’ll see the Shopping List page instead. This logged-in state is saved as a Boolean value in the app’s local storage using the shared_preferences package.

The user can go to the Create Account page for signing up or stay on the Login page, where they can log in and then navigate to the Shopping List page.

Note that this tutorial won’t cover the implementation of a functional login system or any real-world shopping app features. The screens and their corresponding code mimic their UI to explain the navigation concept.

Navigator 1.0

Navigator 1.0 uses the Navigator and Route classes to navigate between pages. If you want to add, or push, a page, use:

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) {
    return MyNewScreen();
  }),
);

Here, MaterialPageRoute returns an instance of your new screen, i.e. MyNewScreen.

To remove, or pop, the current page, use:

Navigator.pop(context);

These operations are straightforward, but things get interesting if you have a use case that requires recreating a set of pages, such as for deep linking.

In the context of mobile apps, deep linking consists of using a uniform resource identifier (URI) that links to a specific location within a mobile app rather than launching the app.

For example, while building an e-commerce app, you may want the user to go to a product page when they tap the “Product X is now on Sale!” notification. To handle this, the app needs to clear the current navigation stack of the app, add the home screen that displays products in a list and then add the product page to this stack of pages. With Navigator 1.0, this is difficult.

Luckily, Navigator 2.0 provides a lot more flexibility for such a use case.

Navigator 2.0

Unlike Navigator 1.0, which uses an imperative style of programming, Navigator 2.0 uses a declarative style. As a result, it feels more “Flutter-like”. Understanding Navigator 2.0 involves understanding a few of its concepts such as:

  • Page: An abstract class that describes the configuration of a route
  • Router: A class that manages opening and closing pages of an application
  • RouteInformationParser: An abstract class used by the Router‘s widget to parse route information into a configuration
  • RouteInformationProvider: An abstract class that provides route information for the Router‘s widget
  • RouterDelegate: An abstract class used by the Router‘s widget to build and configure a navigating widget
  • BackButtonDispatcher: Reports to a Router when the user taps the back button on platforms that support back buttons (such as Android)
  • TransitionDelegate: The delegate that decides how pages transition in or out of the screen when it’s added or removed.

This article doesn’t cover TransitionDelegate, as in most use cases, DefaultTransitionDelegate does a good job with transitions. If you need to handle transitions between pages in a unique way, you can create your own delegate by extending TransitionDelegate.

Here’s a visual representation of the concepts mentioned above:

The classes in gray are optional to implement when using Navigator 2.0. However, the ones in blue, i.e. RouteInformationParser and RouterDelegate, must be implemented to use Navigator 2.0. You’ll learn about both of these, and the optional BackButtonDispatcher, in the sections below.

Pages Overview

Before you begin to implement any navigation, the next sections will provide an overview of the pages in your starter app.

Login Page

The Login page is the first page to appear after the Splash page if the user hasn’t already logged in:

Login page

Clicking on the Create Account button takes the user to the Create Account page, and pressing the Login button takes the user to the Shopping List page. When pressing the Login button, set the logged-in flag using Shared Preferences to true so that the next time the user logs in, they go straight to the Shopping List page after the Splash page.