Deep Linking in Flutter without Firebase: A Complete Guide for Android and iOS


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.

What Is Deep Linking?

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.

Flutter Deep Linking Using app_links and uni_links

We will use two Flutter packages for handling deep linking:

Step 1: Add Required Packages


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.

Step 2: Set Up Deep Linking for Android


Configure AndroidManifest.xml

For Android, you need to configure deep linking in the AndroidManifest.xml file. This file is located in android/app/src/main/AndroidManifest.xml.

Custom URL Schemes:

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>

App Links:

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.

Configure App Links on Your Website [assetlinks.json]

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.

Step 3: Set Up Deep Linking for iOS Using Xcode


Custom URL Schemes:

Open Your Project in Xcode:

  1. Open the ios folder of your Flutter project in Xcode.
  2. Select your app target from the Project Navigator on the left.

Add a Custom URL Scheme:

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>

Universal Links (App Links):

  1. Enable Associated Domains:

    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
                    
  2. Set Up the apple-app-site-association File:

    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.

Step 4: Implementing Deep Linking in Flutter


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';
        

Listening for Links

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'),
                ),
            ),
        );
    }
}
        

Testing Deep Links

To test the deep linking functionality:

Conclusion

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!