Deep linking is a crucial aspect of modern mobile applications, allowing users to navigate directly to specific content within your app from external sources like web pages, emails, or social media posts. In Flutter, managing deep links can be streamlined with the help of packages like uni_links. This article explores how to use uni_links to simplify handling incoming deep links in your Flutter app, providing code samples and best practices.
What are Deep Links?
Deep links are URIs (Uniform Resource Identifiers) that direct users to a specific location within an app. They can be either:
- Custom Scheme Deep Links: Use a custom scheme (e.g.,
myapp://content/123). - Universal Links (Android App Links and iOS Universal Links): Standard HTTP/HTTPS URLs that link directly to content within the app and verify the app’s ownership of the domain.
Why Use Deep Linking?
- Improved User Experience: Direct users to relevant content quickly.
- Increased Engagement: Drive app engagement from marketing campaigns.
- Seamless Navigation: Provide smooth transitions from external sources.
Using the uni_links Package in Flutter
The uni_links package provides a straightforward way to handle both custom scheme and universal links in your Flutter application. Here’s how to get started:
Step 1: Add the uni_links Dependency
Add the uni_links package to your pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
uni_links: ^0.5.1 # Use the latest version
Then, run flutter pub get to install the package.
Step 2: Configure Deep Links on Each Platform
iOS Configuration (Universal Links)
- Associate Your App with Your Website:
Create an
apple-app-site-associationfile and place it in the.well-knowndirectory of your domain. This file specifies the paths that should be handled by your app.Example
apple-app-site-associationfile:{ "applinks": { "apps": [], "details": [ { "appID": "YOUR_TEAM_ID.com.example.myapp", "paths": [ "/content/*" ] } ] } }Replace
YOUR_TEAM_ID.com.example.myappwith your app’s identifier. - Enable Associated Domains Entitlement:
In Xcode, go to your target’s settings, select “Signing & Capabilities,” and add the “Associated Domains” capability. Add entries for each domain you want to associate with your app, prefixed with
applinks:.Example:
applinks:yourdomain.com
Android Configuration (App Links)
- Verify Your App with Google:
Add an
intent-filterto yourAndroidManifest.xmlfile with theDEFAULT,BROWSABLEcategories, and theACTION_VIEWaction. Configure thedatatags with your scheme and host.Set
android:autoVerify="true"to enable automatic verification. If automatic verification fails, you may need to use the Digital Asset Links file approach. - Digital Asset Links File:
Create a
assetlinks.jsonfile and place it in the.well-knowndirectory of your domain.[ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace": "android_app", "package_name": "com.example.myapp", "sha256_cert_fingerprints": [ "YOUR_SHA256_CERT_FINGERPRINT" ] } } ]Replace
com.example.myappwith your app’s package name andYOUR_SHA256_CERT_FINGERPRINTwith your app’s SHA256 certificate fingerprint.
Step 3: Handle Incoming Links in Flutter
In your Flutter app, use the uni_links package to listen for incoming links. Here’s an example:
import 'package:flutter/material.dart';
import 'package:uni_links/uni_links.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
String? _latestLink = 'Unknown';
String? _latestUri;
@override
void initState() {
super.initState();
_initURIHandler();
_incomingLinkHandler();
}
Future _initURIHandler() async {
// 1. Get the latest initial link
final initialLink = await getInitialLink();
// 2. If the link is not null, parse it and navigate
if (initialLink != null) {
_latestLink = initialLink;
_latestUri = initialLink;
print('Initial Link: $_latestLink');
// TODO: Handle the initial link (parse and navigate)
}
}
Future _incomingLinkHandler() async {
// 1. Listen to the stream of incoming links
uriLinkStream.listen((Uri? uri) {
if (!mounted) return;
print('Received URI: $uri');
setState(() {
_latestUri = uri.toString();
_latestLink = uri.toString() ?? 'Unknown';
});
// TODO: Handle the link (parse and navigate)
}, onError: (Object err) {
if (!mounted) return;
print('Got error : $err');
setState(() {
_latestLink = 'Failed to get latest link: $err.';
_latestUri = 'Failed to get latest link: $err.';
});
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Deep Linking Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Latest Link: $_latestLink',
textAlign: TextAlign.center,
),
],
),
),
),
);
}
}
In this example:
- Import the necessary packages (
uni_linksandflutter/services.dart). - The
_initURIHandler()function fetches the initial link when the app starts. - The
_incomingLinkHandler()function listens for incoming links using theuriLinkStream. - Handle the parsed URI to navigate to the appropriate screen in your app.
Parsing the URI
Once you receive the URI, you need to parse it to extract relevant information. For example, if your deep link is https://yourdomain.com/content/123, you need to extract the content ID (123). Here’s how you can parse the URI:
Uri uri = Uri.parse(_latestUri ?? "");
String? path = uri.path;
List pathSegments = uri.pathSegments;
if (pathSegments.isNotEmpty && pathSegments.contains('content')) {
String contentId = pathSegments[pathSegments.indexOf('content') + 1];
print('Content ID: $contentId');
// Navigate to the content details screen
navigateToContentDetails(context, contentId);
}
Best Practices
- Error Handling: Implement robust error handling to gracefully handle invalid or malformed links.
- Navigation: Use a navigation system that allows deep linking to specific content (e.g., using named routes in Flutter).
- Testing: Thoroughly test your deep link implementation on both Android and iOS devices.
- Security: Validate and sanitize deep link data to prevent security vulnerabilities.
Conclusion
Using the uni_links package simplifies the process of handling incoming deep links in your Flutter application, enabling seamless navigation and improved user experience. By configuring deep links on both Android and iOS platforms and implementing robust link handling in your Flutter code, you can effectively leverage deep linking to enhance app engagement and usability.