It's no news that, come August 25, 2025, Firebase will no longer support dynamic links for Flutter applications. To that effect, we will need to handle the app link (for Android) and the universal link (for iOS) ourselves. And in this article, we will be doing so with the help of onGenerateRoute.
Table of Content
- ๐ Introduction
- โจ AppLink Overview
- โ๏ธ Updating AndroidManifest.xml
- ๐ฆ Creating SHA256
- ๐ช Creating & Hosting assetlinks.json file
- ๐งช Testing and Confirming assetlinks.json
- ๐ Deploy app to PlayStore internal testing
โ Confirm the link is auto verified in the device hardware app settings
๐ฎ๐พโโ๏ธ Adding capability
โ๏ธ Testing Via cmd xcrun
โ๏ธ OnGenerateRoute Setup and Routing to a dynamic page with data
๐ Introduction
Deep or dynamic linking is a great feature that Flutter offers in its application to enable a continuance in data consumption from a website to a mobile application.
For instance, say you have an e-commerce website with products to be sold or an online campaign website where users need to vote or be voted for. A user could share a link to that product/profile with another user, who then clicks on the link to be led to the website to continue their business. In a situation where you have both a website and a mobile app and you want the users to still continue their business through the mobile interface, that is where a deep or dynamic link comes in.
NB: In situations where the shared user does not have the app installed, they'd be redirected to their respective device's stores (Play or Apple Store) to download and continue with the application.
PS: In this article, we will be handling the applink and universal link for Android and iOS, respectively.
โจ AppLink Overview
We will be following the official Android Guidelines.
โ๏ธ Updating AndroidManifest.xml
Navigate to your AndroidManifest.xml file and add the below intent inside your <android> block.
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<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" />
<data android:scheme="http" />
<data android:host="gikwegbu.com" />
<data android:host="www.gikwegbu.com" />
</intent-filter>
NB: You need `flutter_deeplinking_enabled` for it to work; that way, the route can be passed from the Android routing system into our Flutter application.
NB: Please update the `gikwegbu` host with your personal domain name.
๐ฆ Creating SHA256
We will need to create an SHA256 for our application. To do that, open your root project in the terminal and run the below code:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Then copy the SHA256 value that comes up.
๐ช Creating & Hosting AssetLink.json file
You can either use the Statement List Generator and Tester link to Generate your statement and in future, Test your statement. Or simply update the below json file with your own details;
NB: This code MUST be saved in the assetLinks.json file.
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.gikwegbu.app",
"sha256_cert_fingerprints":
["PASTE YOUR OWN SHA256 HERE"]
}
}]
NB: Update the package_name with your app's own.
Congratulations if you've gotten to this place so far; you're a genius. But before we host our json file, we need to do something first. I assume you already have a PlayStore account and an APP created for your currently built application. If you don't, please pause and do so.
There is every tendency that your app already exists in the store, and you just want to include this feature, which is perfect. All I need you to do is get the SHA256 google Auto-created for you application in the integrity section of the console and update the sha256_cert_fingerprints in your AssetLink.json. Remember, it's an array of SHA256 values, so just a comma and the new SHA256 value from PlayStore console.
[{
"relation":
["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.gikwegbu.app",
"sha256_cert_fingerprints":
["PASTE YOUR OWN SHA256 HERE", "PASTE GOOGLE PLAY CONSOLE SHA256 HERE TOO"]
}
}]
Hosting your AssetLink.json file;
For this, you will have to reach out to the person managing the website, as we need to upload our file to a specific directory.
http://gikwegbu.com/.well-known/assetlinks.json
NB: It is very important that you place assetlinks.json inside the .well-known/ directory.
NB: The domain must match what you provided in your AndroidManifest.xml android:host data as well.
NB: Once it has been hosted, make sure it's accessible by visiting http://gikwegbu.com/.well-known/assetlinks.json. If it's accessible, you'll see the json data displayed.
๐งช Testing and Confirming AssetLink.json file
To test if your assetlink.json will be OK, provide the required details in the Statement List Generator and Tester, then click on Test Statement to confirm.
This will crawl your website, to confirm the assetlink.json file is present, and the SHA256 keys are also valid.
As a bonus, try inputing the SHA256 you got from the Google Play Console, to confirm it works too.
๐ Deploy app to PlayStore internal testing
Based on my earlier assumption that you just created the app on your Google Console, we would be deploying to internal testing, just so we could test out our deep links before releasing them to the actual store.
NB: This article won't cover how to build and upload your appbundle to the store.
PS: If you have already released your app, no problem, just continue with the next step.
On your Google Play Console, go to the Deep Links on Side Navigation, If everything we've done so far has worked out well, you should get a pretty dashboard like below.
NB: If there's still an issue, please reach out to me, and I'll be glad to help out.
NB: Once you have uploaded the appbundle to your internal testing, wait for a while (say an hour; honestly, I don't know how long it takes for Google to verify your assetlink and web domains) before installing it.
NB: When you have installed it on your device, go to your flutter app's details, select Set as default, > Supported web addresses and see if the host you provided in the AndroidManifest.xml is/are present there.
โ Confirm the link is auto verified in the device hardware app settings
Because in our AndroidManifest.xml, we set the <intent-filter android:autoVerify="true">, therefore, you shouldn't see the toggle/switch button beside your host.

Approved Hosts
Whoop Whoooop!!!! We just finished Applink on our Android.
PS: Stick around to the end of the article to learn how the routing works with the onGenerateRoute configs in Flutter.
๐ Universal Link Overview
For our iOS application, we will be using a Universal link, which is an exclusive type of deep link to Apple devices that uses either the http or the https schemes.
๐ฎ๐พโโ๏ธ Adding capability
In the next few steps, we will be working closely with XCode via the following steps:
- Open your project in
XCode, - In your
Project Navigator, click on theRunner. - Click the
Runnerin theTARGETSsection. - Select
Signing & Capabilities. - Click on the
+ Capability, - When the
Modalpops up, search forAssociated Domainsand add it.
After adding the Associated Domains, update the current web credential Domains with;
applinks:gikwegbu.com // first input
applinks:www.gikwegbu.com // second input
NB: I like adding more options so my app will be recognized when users try to access it with or without the www.
NB: While the above is the easiest and UI approach of adding the Runner.entitlements to your app, you could just create. a Runner.entitlements file within your ios/Runner/ directory, ad add the below code manually:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:gikwegbu.com</string>
<string>applinks:www.gikwegbu.com</string>
</array>
</dict>
</plist>
NB: gikwegbu.com should be your own domain.
From our Step 3 above, whilst still on the Runner in the TARGET section:
- Click on the
infotab. - Open the
URL Typesdropdown and complete the form with below data:
identifier : your app's bundle Identifier,
URL Schemes: https.
NB: You can get you bundle Identifier from your Signing & Capabilities tab in XCode.
NB: For the iOS routing system to successfully parse the dynamic url back into our Flutter application, we need to add the below data into our info.plist file;
<key>FlutterDeepLinkingEnabled</key>
<true/>
๐ก Creating & Hosting AASA file
Open your project root in the terminal and run the below code:
$ touch apple-app-site-association
Then copy and paste the below code, with your own data;
{
"applinks": {
"apps": [],
"details": [{
"appID": "[TEAM_ID].[APP_BUNDLE_ID]",
"paths": ["[PATH_FOR_REDIRECTION]"]
}]
}
}
NB: To get your Team_ID, just open your apple dev account, you'd see the ID by the top right, underneath your name of your screen,
"paths": [
"/your_path", // Users will be be redirected if they visit <https://gikwegbu.com/your_path>
"/your_path/*", // Users will be redirected if they visit <https://gikwegbu.com/your_path/[shduewjakssd]>
"*", // will be redirected to any link <https://gikwegbu.com/[wild card links]>
"NOT /your_path", // Users will be be redirected to any link other than <https://gikwegbu.com/your_path>
"NOT /your_path/*", // Users be redirected to any link other than <https://gikwegbu.com/your_path/[wild card]>
]
Once you're done with the above, host the AASA file on your domain, within the .well-known/ directory, just like you did with your Android assetlinks.json file.
๐ Confirming Our AASA file
To confirm if the AASA file was properly hosted, once you visit the http://gikwegbu.com/.well-known/apple-app-site-association, the file will automatically be downloaded onto your machine.
NB: gikwegbu will be your own domain.
โ๏ธ Testing Via cmd xcrun
First make sure your XCode is running your Flutter app, Open your terminal and run the below code:
$ xcrun simctl openurl booted https://gikwegbu.com/guest/dsewe
NB: Since we haven't worked on the Routing system in our Flutter app, the above command should simply launch your app.
โ๏ธ OnGenerateRoute Setup and Routing to a dynamic page with data
For an efficient and cleaner codebase, I like to keep all my routes in a separate file.
Within your MaterialApp, in your main.dart file, you can add your onGenerateRoute data and point it to the external routes file.
Image of the main.dart file
Here, we will create a class called Routes;
class Routes {
static Route<dynamic> generateRoute(RouteSettings settings) {
debugPrint('${settings.name} Is the current route' );
if (settings.name!.contains('guest')) {
final page = PreInviteInfoScreen(
code: settings.name!.split('/').last,
);
return MaterialPageRoute(builder: (_) => page);
}
final args = settings.arguments; // For screens that requires arguements to be passed
switch (settings.name) {
case HomeView.routeName:
const page = HomeView();
return MaterialPageRoute(builder: (_) => page);
default:
const page = HomeView();
return MaterialPageRoute(builder: (_) => page);
}
}
}
NB: For more context, say the link our users clicks on is https://www.gikwegbu.com/guest/Uhdys, the if statement, will check if that route has the guest keyword, then extract to get the code as it a URL PATH.
This way, when a user clicks on the link above, only the Uhdys is now being passed as the argument for the next screen immediately the app launches.
THE END
So with the above sets of instructions and examples, you should be able to get the Applink and Universal link ready for your FLutter application. CONGRATULATIONS AND GOOD LUCK.












Top comments (1)
This was super helpful... Thank you.