Navigate directly to specific screens using URLs.
Deep linking is a critical feature in modern mobile applications. It allows apps to open directly to a specific screen or content based on a URL, rather than starting from the default home screen. This enhances user experience, enables marketing campaigns, improves app engagement, and integrates mobile apps with web content or external sources.
Flutter supports deep linking through packages like uni_links, firebase_dynamic_links, and go_router. In this post, we will explore deep linking concepts, setup, implementation, handling parameters, and best practices for Flutter apps.
Understanding Deep Linking
Deep linking refers to the practice of using a URL to open an app to a specific location or screen. There are three main types of deep links:
- Basic Deep Links: Open the app if installed and navigate to a specific screen using a URL scheme.
- Deferred Deep Links: Navigate to a specific screen even if the app is not installed yet, typically via installation.
- Universal Links / App Links: Work across platforms, redirecting users to the app if installed or to a website if not.
Benefits of deep linking:
- Direct navigation: Users land directly on relevant content.
- Enhanced user engagement: Reduces friction in multi-step navigation.
- Marketing integration: Links in emails, ads, or social media open specific app content.
- Improved onboarding: Users can reach specific features or promotions directly.
Configuring Deep Linking in Flutter
To enable deep linking, you need to configure your app for both Android and iOS.
Android Setup
- Open
AndroidManifest.xml. - Add an
<intent-filter>to your main activity:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:scheme="myapp"
android:host="example.com"
android:pathPrefix="/details"/>
</intent-filter>
android:schemedefines the URL scheme (e.g., myapp://).android:hostdefines the host.android:pathPrefixspecifies which path opens the app.
iOS Setup
- Open
Info.plist. - Add a URL type:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.example.myapp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
CFBundleURLSchemesdefines the custom URL scheme.- Optional: Configure
Associated Domainsfor universal links.
Handling Deep Links in Flutter
Flutter does not handle deep links natively, so you need packages like:
- uni_links: For basic and universal deep links.
- firebase_dynamic_links: For advanced deferred deep linking with analytics.
- go_router: Simplifies routing and deep linking integration.
Using uni_links
uni_links allows handling both URI links and incoming links when the app is running or launched from a URL.
Installation
Add to pubspec.yaml:
dependencies:
uni_links: ^0.5.1
Listening to Incoming Links
import 'package:uni_links/uni_links.dart';
import 'dart:async';
import 'package:flutter/material.dart';
class DeepLinkHandler extends StatefulWidget {
@override
_DeepLinkHandlerState createState() => _DeepLinkHandlerState();
}
class _DeepLinkHandlerState extends State<DeepLinkHandler> {
StreamSubscription? _sub;
@override
void initState() {
super.initState();
_sub = uriLinkStream.listen((Uri? uri) {
if (uri != null) {
print('Received URI: $uri');
_handleDeepLink(uri);
}
}, onError: (err) {
print('Failed to receive URI: $err');
});
}
void _handleDeepLink(Uri uri) {
if (uri.pathSegments.contains('details')) {
final id = uri.queryParameters['id'];
Navigator.pushNamed(context, '/details', arguments: id);
}
}
@override
void dispose() {
_sub?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Deep Link Handler')),
body: Center(child: Text('Listening for deep links...')),
);
}
}
uriLinkStreamlistens to incoming deep links while the app is running._handleDeepLinkparses the URL and navigates to the appropriate screen.
Passing Parameters via Deep Links
Deep links often include parameters to identify specific content.
Example URL:
myapp://example.com/details?id=123
id=123is a query parameter.- You can retrieve it using
uri.queryParameters['id'].
Navigating to Specific Screens
Deep links are typically used to navigate users directly to a specific screen:
void _handleDeepLink(Uri uri) {
if (uri.pathSegments.contains('details')) {
final id = uri.queryParameters['id'];
Navigator.pushNamed(context, '/details', arguments: id);
}
}
- This ensures that users bypass unnecessary intermediate screens.
- Ideal for content-driven apps like e-commerce, news, or social media.
Using Firebase Dynamic Links
Firebase Dynamic Links provide additional features:
- Works across Android and iOS.
- Supports deferred deep linking: Users reach the correct screen after installing the app.
- Analytics tracking for link engagement.
Setup
- Configure Firebase in your Flutter project.
- Enable Dynamic Links in the Firebase Console.
- Add
firebase_dynamic_linkstopubspec.yaml:
dependencies:
firebase_dynamic_links: ^5.0.0
Listening to Dynamic Links
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) {
final Uri uri = dynamicLinkData.link;
if (uri.pathSegments.contains('details')) {
final id = uri.queryParameters['id'];
Navigator.pushNamed(context, '/details', arguments: id);
}
});
- Provides robust cross-platform support.
- Ensures links work even after app installation.
Using go_router for Deep Linking
go_router simplifies deep linking and navigation management.
Installation
dependencies:
go_router: ^7.2.0
Setting Up Routes
final GoRouter router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) {
final id = state.params['id'];
return DetailScreen(id: id);
},
),
],
);
- Supports path parameters and query parameters.
- Integrates seamlessly with Navigator and URL schemes.
Navigating via URL
context.go('/details/123');
go_routerautomatically parses parameters and navigates to the target screen.
Deferred Deep Linking
Deferred deep links ensure users reach a specific screen even if the app is not installed.
- User clicks a dynamic link.
- App stores the intended destination.
- After installation, the app navigates to the original screen automatically.
- Useful for marketing campaigns, promotions, and onboarding flows.
- Supported by Firebase Dynamic Links.
Handling Edge Cases
- App already running: Listen for links using
uriLinkStreamoronLink. - App not running: Retrieve initial link using
getInitialUri().
Uri? initialUri = await getInitialUri();
if (initialUri != null) {
_handleDeepLink(initialUri);
}
- Invalid links: Validate URLs before navigation to prevent crashes.
- Multiple query parameters: Use
uri.queryParametersoruri.queryParametersAll.
Testing Deep Links
- Android: Use
adbto send an intent:
adb shell am start -a android.intent.action.VIEW -d "myapp://example.com/details?id=123" com.example.myapp
- iOS: Use Xcode or Safari to test URL schemes.
- Firebase Dynamic Links: Use Firebase console to generate test links.
Best Practices
- Centralize deep link handling: Avoid duplicating logic in multiple widgets.
- Validate all incoming URLs: Prevent errors or malicious deep links.
- Use named routes or
go_router: Simplifies parameter parsing and navigation. - Support both app running and app not running states: Ensure links work consistently.
- Use dynamic links for marketing campaigns: Track engagement and handle deferred deep links.
- Combine with authentication: Redirect users to login if required before reaching the target screen.
- Log deep link events: Helps in analytics and debugging.
Real-World Examples
E-Commerce App
- User clicks a link from an email:
myapp://example.com/product?id=456. - App opens product details screen for product 456.
- If not installed, the user installs the app and lands on the same product page.
Social Media App
- Link shared:
myapp://example.com/profile?user=john_doe. - App opens John Doe’s profile directly, bypassing home feed.
- Enhances user engagement and content discoverability.
News App
- Link from website:
myapp://example.com/article?id=789. - App opens the exact article directly.
- Supports deferred deep links for new users.
Leave a Reply