Finding a solid replacement for Firebase Dynamic Links in Flutter can be a challenge. The ecosystem is filled with complex solutions or packages that haven’t been maintained. When all you need is a reliable way to get users from a link to a specific screen in your app, you shouldn’t have to fight with a heavy, complicated SDK.
This guide provides a simple, copy-paste-ready solution. We will walk you through a complete, step-by-step tutorial on how to implement Flutter dynamic links using the Tapp SDK. It’s the cleanest and most straightforward way to handle deep linking after the FDL shutdown.

Prerequisites
Before we start, make sure you have the following ready:
- A Tapp account and your free API key.
- An existing Flutter project.
- Your app’s associated iOS Bundle ID and Android Package Name configured in your Tapp dashboard.
Step 1: Add the Tapp Flutter SDK
First, add the Tapp package to your Flutter project. It’s a single line in your terminal.
flutter pub add tappso_sdk
This will add the latest version of the Tapp SDK to your pubspec.yaml
file.
Step 2: Initialize the SDK
The next step is to configure the SDK when your app starts. The best place to do this is in your main()
function, right before you run your app. This ensures that the Tapp service is ready to listen for incoming deep links from the moment your app launches.
import 'package:flutter/material.dart';
import 'package:tappso_sdk/tappso_sdk.dart';
void main() async {
// Ensure Flutter engine is initialized
WidgetsFlutterBinding.ensureInitialized();
// Initialize Tapp with your API key
await Tappso.configure(apiKey: "YOUR_API_KEY");
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tapp Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
Step 3: Listen for Deep Links
This is the core of your implementation. The Tapp SDK makes it easy to set up a listener that fires whenever a deep link is resolved, whether the app was just installed (deferred) or already on the device.
We recommend setting up this listener in your main widget’s initState
.
import 'package:flutter/material.dart';
import 'package:tappso_sdk/tappso_sdk.dart';
import 'dart:async';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
StreamSubscription<Deeplink>? _deeplinkSubscription;
@override
void initState() {
super.initState();
initDeeplinkListener();
}
void initDeeplinkListener() {
_deeplinkSubscription = Tappso.onDeeplinkResolved.listen((deeplink) {
// Deep link received! Now you can use the data.
print('Tapp Deeplink Resolved!');
// Access your custom parameters
final productId = deeplink.params['productId'];
if (productId != null) {
print('Navigating to product page with ID: $productId');
// Use your app's navigation logic here
// e.g., Navigator.push(context, ProductScreen.route(productId));
}
// Check if this was a deferred deep link from a new install
if (deeplink.isFirst) {
print('This link was opened on a fresh install.');
// You could trigger a special onboarding flow here
}
});
}
@override
void dispose() {
// Clean up the subscription when the widget is disposed
_deeplinkSubscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Tapp Flutter Guide'),
),
body: const Center(
child: Text('Listening for Tapp deep links...'),
),
);
}
}
With this code, your app is now fully equipped to handle dynamic links in Flutter. The onDeeplinkResolved
stream provides all the data you need to route users effectively.
Step 4: Platform-Specific Configuration
To ensure deep links work reliably, you need to add some configuration for iOS and Android.
For iOS
You need to associate your domain with your app. Add the following to your ios/Runner/Info.plist
file.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>YOUR_URL_SCHEME</string> <!-- e.g., "tappso-demo" -->
</array>
</dict>
</array>
For Android
You need to add an intent-filter
to your main activity in the android/app/src/main/AndroidManifest.xml
file.
<activity
android:name=".MainActivity"
...>
<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="YOUR_URL_SCHEME" /> <!-- e.g., "tappso-demo" -->
</intent-filter>
</activity>
This platform setup ensures the operating system knows to open your app when a corresponding link is clicked.
Conclusion
That’s all it takes. You’ve successfully implemented a powerful replacement for Firebase Dynamic Links in your Flutter app. By following these simple steps, you’ve added a lightweight SDK, initialized it, and set up a robust listener to handle all your deep linking needs.
Your migration doesn’t have to be a roadblock. Get your free API key and start building with our Flutter SDK today.
For a deeper dive into the migration process, check out our complete Technical Guide: How to Replace Firebase Dynamic links with Tapp for iOS & Android.