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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Flutter Navigator 2.0 and Deep Links
40 mins
- Getting Started
- Navigator 1.0
- Navigator 2.0
- Pages Overview
- Login Page
- Create Account Page
- Shopping List Page
- Details Page
- Cart Page
- Checkout Page
- Settings Page
- Pages Setup
- AppState
- RouterDelegate
- Implementing build
- Removing Pages
- Creating and Adding a Page
- Modifying the Contents
- RouteInformationParser
- Root Widget and Router
- Navigating Between Pages
- Splash Page Navigation
- BackButtonDispatcher
- Deep Linking
- Parse Deep Link URI
- Testing Android URIs
- Where to Go From Here?
Deep Linking
To implement deep links, this tutorial uses the uni_links package.
This package helps with deep links on Android, as well as Universal Links and Custom URL Schemes on iOS. To handle deep links on Android, modify the AndroidManifest.xml file in the android/app/src/main directory. For Android, add an <intent-filter>
tag inside the MainActivity
's <activity>
tag as follows:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="navapp"
android:host="deeplinks" />
</intent-filter>
For iOS, modify ios/Runner/Info.plist by adding:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>deeplinks</string>
<key>CFBundleURLSchemes</key>
<array>
<string>navapp</string>
</array>
</dict>
</array>
Both of these changes add a scheme named navapp to the app where navapp means Navigation App. In terms of deep links, this means this app can open URLs that look like navapp://deeplinks
Now that you know how to make deep links open your app, follow the steps below to understand how to consume the link the user clicked on.
Parse Deep Link URI
Open the router_delegate.dart file and add parseRoute
, which takes a Uri
as an argument, parses the path and sets the page(s):
void parseRoute(Uri uri) {
// 1
if (uri.pathSegments.isEmpty) {
setNewRoutePath(SplashPageConfig);
return;
}
// 2
// Handle navapp://deeplinks/details/#
if (uri.pathSegments.length == 2) {
if (uri.pathSegments[0] == 'details') {
// 3
pushWidget(Details(int.parse(uri.pathSegments[1])), DetailsPageConfig);
}
} else if (uri.pathSegments.length == 1) {
final path = uri.pathSegments[0];
// 4
switch (path) {
case 'splash':
replaceAll(SplashPageConfig);
break;
case 'login':
replaceAll(LoginPageConfig);
break;
case 'createAccount':
// 5
setPath([
_createPage(Login(), LoginPageConfig),
_createPage(CreateAccount(), CreateAccountPageConfig)
]);
break;
case 'listItems':
replaceAll(ListItemsPageConfig);
break;
case 'cart':
setPath([
_createPage(ListItems(), ListItemsPageConfig),
_createPage(Cart(), CartPageConfig)
]);
break;
case 'checkout':
setPath([
_createPage(ListItems(), ListItemsPageConfig),
_createPage(Checkout(), CheckoutPageConfig)
]);
break;
case 'settings':
setPath([
_createPage(ListItems(), ListItemsPageConfig),
_createPage(Settings(), SettingsPageConfig)
]);
break;
}
}
}
In the code above:
- Check if there are no
pathSegments
in the URI. If there are, navigate to the Splash page. - Handle the special case for the Details page, as the
path
will have twopathSegments
. - Parse the item number and push a Details page with the item number. In a real app, this item number could be a product's unique ID.
- Use
path
as an input for theswitch
case. - In this case and other cases, push the pages necessary to navigate to the destination using
setPath
.
Next, to link parseRoute
to the root widget's router
, open main.dart.
Add the following code after ShoppingBackButtonDispatcher backButtonDispatcher;
:
StreamSubscription _linkSubscription;
_linkSubscription
is a StreamSubscription
for listening to incoming links. Call .cancel()
on it to dispose of the stream.
To do so, add:
_linkSubscription?.cancel();
before super.dispose();
. Now add the missing initPlatformState
, which is responsible for setting up the listener for the deep links:
// Platform messages are asynchronous, so declare them with the async keyword.
Future<void> initPlatformState() async {
// Attach a listener to the Uri links stream
// 1
_linkSubscription = getUriLinksStream().listen((Uri uri) {
if (!mounted) return;
setState(() {
// 2
delegate.parseRoute(uri);
});
}, onError: (Object err) {
print('Got error $err');
});
}
Here's what you do in the code above:
- Initialize
StreamSubcription
by listening for any deep link events. - Have the app's
delegate
parse theuri
and then navigate using the previously definedparseRoute
.
At this point, you've implemented deep links, so stop the running instance of your app and re-run it to include these changes. Don't use hot restart or hot reload because there were changes on the native Android and native iOS side of the project and they aren't considered by these two tools.
Testing Android URIs
To test your deep links on Android, the easiest way is from the command line.
Open Terminal on macOS or Linux or CMD on Windows and verify that the app navigates to the Settings page using the following adb shell command:
adb shell 'am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "navapp://deeplinks/settings"'
Notice that this adb command includes the app's deep link scheme
navapp
and host
deeplinks
from Android Manifest.xml.
To navigate to the Details page with the index of the item as 1
, try the following command:
adb shell 'am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "navapp://deeplinks/details/1"'
To navigate to the Cart page, try the following command:
adb shell 'am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "navapp://deeplinks/cart"'
You'll see your app navigates to the target page. If that's not the case, check the logs to see if there are any errors.
Where to Go From Here?
Download the final version of this project using the Download Materials button at the top or bottom of this tutorial.
Congratulations! That was a lot of code, but it should help you whenever you plan to implement your own RouterDelegate with Navigator 2.0.
Check out the following links to learn more about some of the concepts in this tutorial:
- Navigator 2.0: Navigator Refactoring.
- Github Issue: Navigator 2.0 Refactoring
- Navigator 2.0 Design Doc: Navigator 2.0 and Router
- Get: Counter app using Get example
- uni_links
We hope you enjoyed this tutorial, and if you have any questions or comments, please join the forum discussion below!