In mobile app development, deep linking is essential for enhancing user experience by directing users to specific parts of your app via links. While Firebase Dynamic Links is a popular choice for deep linking, it is possible to implement deep linking without Firebase. In this blog, we will walk through how to set up deep linking in Flutter for both Android and iOS using the app_links and uni_links packages. We will also cover the required steps for setting up iOS using Xcode.
Deep linking allows an app to be opened by clicking a URL, which can point to specific content within the app. For example, clicking a URL like myapp://profile can open your app directly to the user’s profile page.
We will use two Flutter packages for handling deep linking:
To get started, add app_links and uni_links to your pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
app_links: ^3.3.0
uni_links: ^0.5.1
Run flutter pub get to install the packages.
For Android, you need to configure deep linking in the AndroidManifest.xml file. This file is located in android/app/src/main/AndroidManifest.xml.
To handle deep links with a custom URL scheme (like myapp://), add the following inside the <activity> tag:
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<!-- Replace 'myapp' with your custom scheme -->
<data android:scheme="myapp"/>
</intent-filter>
If you want to support App Links, where you use a web URL (like https://yourdomain.com), add another intent filter:
<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="https" android:host="yourdomain.com" android:pathPrefix="/app"/>
</intent-filter>
This allows your app to respond to URLs such as https://yourdomain.com/app/profile.
To verify the association of your app with the domain, add an assetlinks.json file to your web server:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.myapp",
"sha256_cert_fingerprints": ["YOUR_CERTIFICATE_SHA256_FINGERPRINT"]
}
}
]
Replace com.example.myapp with your app’s package name and provide the SHA-256 fingerprint from your app's signing certificate.
Open Your Project in Xcode:
ios folder of your Flutter project in Xcode.Select the Info tab of your target, scroll down to URL Types, and click + to add a new URL scheme. In the Identifier field, enter CustomURLScheme. In the URL Schemes field, enter your scheme (e.g., myapp).
Alternatively, you can edit the Info.plist manually:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string> <!-- Replace with your custom scheme -->
</array>
</dict>
</array>
Go to the Signing & Capabilities tab of your target. Click the + Capability button and add Associated Domains. Under the Domains section, add your domain in this format:
applinks:yourdomain.com
On your website, host a file called apple-app-site-association at the root (https://yourdomain.com/apple-app-site-association). The file should contain the following:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "YOUR_TEAM_ID.com.example.myapp",
"paths": [ "/app/*" ]
}
]
}
}
Replace YOUR_TEAM_ID with your Apple Developer Team ID and com.example.myapp with your app's bundle identifier.
Now that we have set up the platform-specific configurations, we can implement deep linking logic in our Flutter app.
In your main Dart file (e.g., main.dart), import the necessary packages:
import 'package:flutter/material.dart';
import 'package:app_links/app_links.dart';
import 'package:uni_links/uni_links.dart';
Use a Stream to listen for incoming links:
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
String? _incomingLink;
@override
void initState() {
super.initState();
_initDeepLinking();
}
void _initDeepLinking() async {
// For uni_links
linkStream.listen((String? link) {
setState(() {
_incomingLink = link;
});
});
// For app_links
final appLinks = AppLinks();
appLinks.uriLinkStream.listen((Uri? uri) {
setState(() {
_incomingLink = uri?.toString();
});
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Deep Linking Demo')),
body: Center(
child: Text(_incomingLink ?? 'No incoming link'),
),
),
);
}
}
To test the deep linking functionality:
myapp://profile from your browser or via ADB command:
adb shell am start -W -a android.intent.action.VIEW -d "myapp://profile" com.example.myapp
assetlinks.json file is correctly set up.Deep linking in Flutter without Firebase is not only possible but also straightforward with the use of app_links and uni_links packages. By following the steps outlined in this guide, you can implement deep linking functionality in your Flutter app for both Android and iOS.
Happy coding!