Implementing Deep Links and App Links in Flutter

Summary
Summary
Summary
Summary

This tutorial explains Android App Links and iOS Universal Links setup, hosting assetlinks.json/AASA, and how to handle deep links in Flutter using uni_links. It shows code for cold-start and runtime link handling, parsing URIs to routes, and outlines testing and troubleshooting steps.

This tutorial explains Android App Links and iOS Universal Links setup, hosting assetlinks.json/AASA, and how to handle deep links in Flutter using uni_links. It shows code for cold-start and runtime link handling, parsing URIs to routes, and outlines testing and troubleshooting steps.

This tutorial explains Android App Links and iOS Universal Links setup, hosting assetlinks.json/AASA, and how to handle deep links in Flutter using uni_links. It shows code for cold-start and runtime link handling, parsing URIs to routes, and outlines testing and troubleshooting steps.

This tutorial explains Android App Links and iOS Universal Links setup, hosting assetlinks.json/AASA, and how to handle deep links in Flutter using uni_links. It shows code for cold-start and runtime link handling, parsing URIs to routes, and outlines testing and troubleshooting steps.

Key insights:
Key insights:
Key insights:
Key insights:
  • Configuring Android App Links: Host assetlinks.json with your package name and SHA256 and add intent-filters with autoVerify for verified HTTP links.

  • Configuring iOS Universal Links: Enable Associated Domains and host an AASA file containing your appID and allowed paths; ensure correct content-type and no redirects.

  • Using uni_links In Flutter: Use getInitialUri for cold starts and uriLinkStream for runtime events; centralize URI parsing and navigation.

  • Handling Cold Start And Background Links: Await getInitialUri early and keep a persistent uriLinkStream subscription to receive background links reliably.

  • Testing And Troubleshooting: Use adb and device logs on Android and device logs/ngrok for iOS; common failures usually trace back to assetlinks.json or AASA misconfiguration.

Introduction

Deep links and app links let you open specific screens in your Flutter app from a URL, push notifications, or another app. Deep links are generic URL schemes; App Links (Android) and Universal Links (iOS) are verified HTTP(s) links that bypass the “Open With” dialog and increase security. This tutorial covers configuration for Android and iOS and how to handle links in Flutter using a code-forward approach.

Configuring Android App Links

1) Add intent filters in AndroidManifest.xml for the activities that should receive the HTTP(S) URL. Use the host and pathPrefix attributes to scope the URLs. Example intent-filter (Android native step):

  • Create a Digital Asset Links file (assetlinks.json) and host it at https:///.well-known/assetlinks.json. It must reference your app’s package name and signing certificate SHA256.

  • Verify package name and SHA256 with keytool (release key) to ensure the JSON matches.

  • Add the Android manifest intent-filters for autoVerify="true" so OS attempts verification at install.

Tips: Use HTTPS URLs only for App Links. For development, assetlinks.json can be hosted on a staging domain; use adb to test linking behavior.

Configuring iOS Universal Links

1) Enable Associated Domains in the Xcode project targets > Signing & Capabilities.

2) Add the domain prefixed with applinks:, e.g. applinks:example.com.

3) Host an Apple App Site Association (AASA) file at https:///.well-known/apple-app-site-association or at the root. It must list the app’s appID (teamID.bundleID) and the paths the app handles.


Important: AASA must be delivered with Content-Type: application/json and without redirects. Use the exact team ID from Apple Developer and the bundle identifier in the app ID string. For local testing use a tunneling endpoint (ngrok) and verify with device logs.

Handling Links in Flutter

Use a platform-aware package to receive incoming links. Two common choices are uni_links for general deep links and firebase_dynamic_links if you need analytics, campaign tracking, or deferred deep linking.

Install uni_links and handle both cold start and background events. The two core entry points are getInitialUri (cold start) and uriLinkStream (when app is already running). The snippet below demonstrates a concise pattern in a StatefulWidget to handle both cases and route to an internal path.

import 'package:uni_links/uni_links.dart';
import 'dart:async';

StreamSubscription? _sub;

void initUniLinks() async {
  final initial = await getInitialUri();
  if (initial != null) _handleUri(initial);
  _sub = uriLinkStream.listen((Uri? uri) { if (uri != null) _handleUri(uri); });
}

void disposeUniLinks() => _sub?.cancel();

void _handleUri(Uri uri) {
  // parse and navigate: /product/123 -> go to ProductScreen(id: '123')
}

Keep parsing logic centralized: map URIs to route names or to a navigation function. For Flutter Navigator 2.0 (Router API) integrate the parsed route into your route state for deep link-driven navigation.

Second snippet: a compact navigation helper that demonstrates parsing a simple path and pushing a route.

void _handleUri(Uri uri) {
  final segments = uri.pathSegments; 
  if (segments.isNotEmpty && segments[0] == 'product') {
    final id = segments.length > 1 ? segments[1] : null;
    if (id != null) Navigator.of(context).pushNamed('/product', arguments: id);
  }
}

Security: validate tokens or parameter values from the URL before using them. Never trust a URL to authorize sensitive actions without backend verification.

Testing And Troubleshooting

Android testing: use adb to simulate an intent:

adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://example.com/product/123"

Check logcat for verification errors. If autoVerify fails, verify the assetlinks.json content and its SHA256 fingerprint.

iOS testing: use a device (Universal Links do not work on simulator for all cases). Use the Notes app or Terminal to open a link (xcrun simctl openurl for simulator). Inspect device logs for AASA fetch and errors. Ensure AASA is delivered as application/json and contains correct appID and paths.

Common issues and fixes:

  • Links open in browser instead of app: assetlinks.json/AASA misconfigured or missing. Verify them first.

  • Cold start link arrives null: ensure getInitialUri is awaited early (e.g., in initState) and that platform plugin initialization occurs before routing.

  • Background link not delivered: ensure uriLinkStream subscription is active and not disposed.

Consider analytics and deferred deep linking: Firebase Dynamic Links can create links that open the Play Store / App Store and deliver parameters after install. Use Firebase SDK if you need those features.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Implementing deep links and app links requires native configuration on Android and iOS and careful handling in Flutter to manage cold-start and in-app link navigation. Use uni_links or Firebase Dynamic Links depending on feature needs, verify assetlinks.json/AASA files, and centralize parsing and routing logic. With correct setup you can provide a seamless, secure navigation experience from URLs to specific screens in your Flutter app.

Introduction

Deep links and app links let you open specific screens in your Flutter app from a URL, push notifications, or another app. Deep links are generic URL schemes; App Links (Android) and Universal Links (iOS) are verified HTTP(s) links that bypass the “Open With” dialog and increase security. This tutorial covers configuration for Android and iOS and how to handle links in Flutter using a code-forward approach.

Configuring Android App Links

1) Add intent filters in AndroidManifest.xml for the activities that should receive the HTTP(S) URL. Use the host and pathPrefix attributes to scope the URLs. Example intent-filter (Android native step):

  • Create a Digital Asset Links file (assetlinks.json) and host it at https:///.well-known/assetlinks.json. It must reference your app’s package name and signing certificate SHA256.

  • Verify package name and SHA256 with keytool (release key) to ensure the JSON matches.

  • Add the Android manifest intent-filters for autoVerify="true" so OS attempts verification at install.

Tips: Use HTTPS URLs only for App Links. For development, assetlinks.json can be hosted on a staging domain; use adb to test linking behavior.

Configuring iOS Universal Links

1) Enable Associated Domains in the Xcode project targets > Signing & Capabilities.

2) Add the domain prefixed with applinks:, e.g. applinks:example.com.

3) Host an Apple App Site Association (AASA) file at https:///.well-known/apple-app-site-association or at the root. It must list the app’s appID (teamID.bundleID) and the paths the app handles.


Important: AASA must be delivered with Content-Type: application/json and without redirects. Use the exact team ID from Apple Developer and the bundle identifier in the app ID string. For local testing use a tunneling endpoint (ngrok) and verify with device logs.

Handling Links in Flutter

Use a platform-aware package to receive incoming links. Two common choices are uni_links for general deep links and firebase_dynamic_links if you need analytics, campaign tracking, or deferred deep linking.

Install uni_links and handle both cold start and background events. The two core entry points are getInitialUri (cold start) and uriLinkStream (when app is already running). The snippet below demonstrates a concise pattern in a StatefulWidget to handle both cases and route to an internal path.

import 'package:uni_links/uni_links.dart';
import 'dart:async';

StreamSubscription? _sub;

void initUniLinks() async {
  final initial = await getInitialUri();
  if (initial != null) _handleUri(initial);
  _sub = uriLinkStream.listen((Uri? uri) { if (uri != null) _handleUri(uri); });
}

void disposeUniLinks() => _sub?.cancel();

void _handleUri(Uri uri) {
  // parse and navigate: /product/123 -> go to ProductScreen(id: '123')
}

Keep parsing logic centralized: map URIs to route names or to a navigation function. For Flutter Navigator 2.0 (Router API) integrate the parsed route into your route state for deep link-driven navigation.

Second snippet: a compact navigation helper that demonstrates parsing a simple path and pushing a route.

void _handleUri(Uri uri) {
  final segments = uri.pathSegments; 
  if (segments.isNotEmpty && segments[0] == 'product') {
    final id = segments.length > 1 ? segments[1] : null;
    if (id != null) Navigator.of(context).pushNamed('/product', arguments: id);
  }
}

Security: validate tokens or parameter values from the URL before using them. Never trust a URL to authorize sensitive actions without backend verification.

Testing And Troubleshooting

Android testing: use adb to simulate an intent:

adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://example.com/product/123"

Check logcat for verification errors. If autoVerify fails, verify the assetlinks.json content and its SHA256 fingerprint.

iOS testing: use a device (Universal Links do not work on simulator for all cases). Use the Notes app or Terminal to open a link (xcrun simctl openurl for simulator). Inspect device logs for AASA fetch and errors. Ensure AASA is delivered as application/json and contains correct appID and paths.

Common issues and fixes:

  • Links open in browser instead of app: assetlinks.json/AASA misconfigured or missing. Verify them first.

  • Cold start link arrives null: ensure getInitialUri is awaited early (e.g., in initState) and that platform plugin initialization occurs before routing.

  • Background link not delivered: ensure uriLinkStream subscription is active and not disposed.

Consider analytics and deferred deep linking: Firebase Dynamic Links can create links that open the Play Store / App Store and deliver parameters after install. Use Firebase SDK if you need those features.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Implementing deep links and app links requires native configuration on Android and iOS and careful handling in Flutter to manage cold-start and in-app link navigation. Use uni_links or Firebase Dynamic Links depending on feature needs, verify assetlinks.json/AASA files, and centralize parsing and routing logic. With correct setup you can provide a seamless, secure navigation experience from URLs to specific screens in your Flutter app.

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Other Insights

Other Insights

Other Insights

Other Insights

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025