Migrate from Dynamic Links to App Links & Universal Links

This migration guide focuses on using App Links and Universal Links, optionally using Firebase Hosting to host your app-site association files.

This migration replaces the following Firebase Dynamic Links features:

Feature Firebase Dynamic Links App Links / Universal Links
Route users to the correct store for their device from a single link click
Provide users with a continuation of journey after downloading and installing your app using a deferred deep link
Provide users with a contextual experience using deep-linked content in your app (when already installed)
Provide analytics data related to dynamic link click events
Provide the ability to create short link URLs

If you continue to need other Firebase Dynamic Link features for your migration that aren't supported in this guide, see other migration scenarios in the Dynamic Links Deprecation FAQ documentation.

Suppose you have a Firebase Dynamic Link that looks like this:

Dynamic Link Example
Link name Welcome to Example.com
Deep link https://example.web.app/welcome
Android app com.example.android
Apple app com.example.ios
Long Dynamic Link https://example.page.link/?link=https://example.web.app/welcome&apn=com.example.android&isi=123456789&ibi=com.example.iuos
Short Dynamic Link https://example.page.link/m9Mm

The goal of this migration guide is to replace Firebase Dynamic Links like this:

https://example.page.link/m9Mm

With App Link / Universal Link deep links that look like this:

https://your-project-domain.web.app/welcome

Note that the App Link / Universal Link deep link will provide the following to your users:

  • A deep link they can click that will open your app when already installed
  • A continuation of their user journey navigating them to a specific part of your app when it is opened

However, the App Link / Universal Link deep link will not provide the following behaviors for your users (which Firebase Dynamic Links previously did):

  • Navigating users to the correct store for their device to download and install your app
  • Providing a continuation of their user journey after downloading, installing and opening the app for the first time

Note the differences in behavior and functionality of these App Links / Universal Links compared to Firebase Dynamic Links called out in the table above.

Before you begin

Firebase Dynamic Links utilizes App Links (on Android) and Universal Links (on iOS) in its own underlying implementation in order to provide deep-linking functionality after your app is already installed.

This guide walks through how to create your own App Links and Universal Links using Firebase Hosting to replace that part of the functionality provided by Firebase Dynamic Links while migrating your Firebase Dynamic Links to the new App Links / Universal Links migration solution.

You'll need the following pieces of information in order to complete your migration:

  • The Firebase Dynamic Links you intend to migrate
  • The deep-link URL parameters included in your dynamic links
  • The domain you plan to use to replace your previous Firebase Dynamic Links domain (if applicable)

You can use the Export Dynamic Links Metadata guide to export your existing link metadata and obtain the information listed above.

Migration steps overview

  1. Provision a new domain (if you don't already have one you want to use) to host your App Link / Universal Link configuration files using Firebase Hosting.

  2. Create and host your App Link / Universal Link configuration files on your hosting domain.

  3. Create new App Links / Universal Links matching the deep-link schema used in your Firebase Dynamic Links.

  4. Update your Android / iOS apps and application code to receive deep-links.

  5. Testing your App Links / Universal Links integrations.

  6. Replace your published or shared Firebase Dynamic Links with App Links and Universal Links.

The first step will be common to both the App Links or Universal Link migration flows. The remainder will vary depending on the platform, so navigate to the section of the guide below depending on which platform you would like to migrate first.

Choose a domain

The first step is to choose a domain you would like to use for your App Links / Universal Links. This will be the domain that will be used for the new links that you will share out to your users.

If you use Firebase Hosting, project subdomains with the format your-project-domain.web.app or your-project-domain.firebaseapp.com are automatically provisioned at no cost. You can optionally use a custom domain with or without Firebase Hosting to host your App Link / Universal Link configuration files as well.

Set up Firebase Hosting

Next, you'll need to set up and configure your Firebase Hosting instance.

By the time you're done setting up your Firebase Hosting instance, you'll have a domain similar to your-project-domain.web.app`, or a custom domain if you prefer.

In order to use App Links, you must host a configuration file that helps establish a secure association between the domain used in your links and your app. For App Links, this is the assetlinks.json file.

Steps to create and host the assetlinks.json file

The assetlinks.json file allows us to provide a list of authorized apps that can handle the contents of the web domain we'll be using for our App Links. The assetlinks.json file itself needs to be hosted in the root of the web domain under the path: /.well-known.

Follow the steps below to complete this configuration:

  1. Create the .well-known folder under the public folder in your Firebase Hosting root directory.

  2. Create a file named assetlinks.json under the .well-known folder.

  3. Copy the following content to your assetlinks.json file, taking note of the meaning of each field below:

    [{
      "relation": ["delegate_permission/common.handle_all_urls"],
      "target": {
        "namespace": "android_app",
        "package_name": "com.example.android",
        "sha256_cert_fingerprints":
          ["01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF"]
      }
    }]
    
    • namespace - refers to the name of the application you want to provide
    • package_name - refers to the applicationId declared in the app's build.gradle file
    • sha256_cert_fingerprints - refers to the SHA256 fingerprint of the keystore file that you use for signing the application.

    You can use the debug.keystore file used by Android Studio to generate a sha256_cert_fingerprints record for debugging purposes. You can find the file at /Users/<username>/.android/debug.keystore on Mac and Linux and C:\Users\<username>\.android\debug.keystore on Windows.

    From this keystore, you can fetch the SHA256 value using the keytool.

    Refer to this section of the App Links documentation for more instructions on completing this step.

    Alternatively you can also use the App Links Assistant in Android Studio to generate the assetlinks.json file contents and configure your application to handle App Links.

  4. Update your firebase.json file to index the file for hosting.

    "headers": [
      {
        "source": "/.well-known/assetlinks.json",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ]
    
  5. Now that we have the assetlinks.json file in place, run firebase deploy to host the changes.

    Note you will need to have the Firebase CLI installed in order to run the above deploy command.

    firebase deploy --only hosting
    
  6. Verify the assetlinks.json file by going to https://your-project-domain.web.app/.well-known/assetlinks.json

In this step, you will recreate the deep-links from your Firebase Dynamic Links using regular deep-link URLs matching the new domain you've created for your App Links.

So for example, let's say you have the following Firebase Dynamic Link:

Dynamic Link Example
Link name Welcome to Example.com
Deep link https://example.web.app/welcome
Android app com.example.android
Apple app com.example.ios
Long Dynamic Link https://example.page.link/?link=https://example.web.app/welcome&apn=com.example.android&isi=123456789&ibi=com.example.iuos
Short Dynamic Link https://example.page.link/m9Mm

In this case, you would extract the deep link parameter - i.e. https://example.web.app/welcome and will now use this as the App Link parameter for your app.

You'll want to repeat this process for each Firebase Dynamic Link you wish to migrate to using App Links / Universal Links, and replicate the deep-linking schema you used.

For example, please see the following set of Firebase Dynamic Links short-links, deep link parameters and migrated deep link values:

Short link Deep link parameter Migrated deep link
yourapp.page.link/welcome https://example.com/welcome yourapp.web.app/welcome
yourapp.page.link/c7sn https://example.com/main/?p=23&t=1 yourapp.web.app/main/?p=23&t=1
yourapp.page.link/social https://example.com/friendinvite/?add=1 yourapp.web.app/friendinvite/?add=1

Next, you'll need to replace any instances of Firebase Dynamic Links that have been published or shared with the new migrated deep links so users will click on those App Links instead of the previous Firebase Dynamic Links.

The next step after selecting a domain, choosing a deep-linking schema and migrating your Firebase Dynamic Links to App Links is to update your Android app and application code to receive the new deep links.

We recommend following the full App Links documentation here or alternatively the Android Studio guide on configuring your app to handle deep links, but the main steps include:

  1. Identifying which activities should handle the respective deep links
  2. Adding an Intent Filter for those activities in your AndroidManifest.xml file
  3. Receiving the deep link in your activities' application code

Let's say that you wanted to use your MainActivity to handle some of your deep links. To do this, you will need to add the following Intent Filter to the MainActivity in your AndroidManifest.xml file:

<activity android:name=".MainActivity"
   android:exported="true">
   <intent-filter>
       <action android:name="android.intent.action.MAIN" />
       <category android:name="android.intent.category.LAUNCHER" />
   </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:host="example.web.app" android:scheme="http"
           android:pathPrefix="/welcome" />
       <data android:host="example.web.app" android:scheme="https"
           android:pathPrefix="/welcome" />
   </intent-filter>
</activity>

In this step, you are specifying that the MainActivity is the destination for handling deep links from the wxample.web.app domain and that includes the /welcome path prefix. Note that you will also need to specify the android:autoVerify="true" attribute, which allows you to designate your app as the default handler for this given type of link.

Finally, you'll need to add the code in your MainActivity to retrieve the deep-link data and use that to drive the deep link experience in your app. This is similar to logic you may have already coded in your app when you integrated with Firebase Dynamic Links.

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.main)

  val  data: Uri? = intent?.data

  val toast = Toast.makeText(this, data, duration)
  toast.show()
}

You can test the App Links you've just created by either running your app on a physical device or in the Android Emulator.

You'll need to create a clickable link using the domain configured for your App Links and then click on that link to ensure that it opens up into your app and navigates you to the intended activity.

Alternatively you can also test your App Links integration using the App Links Assistant in Android Studio, or use the following command for an App Link URL you've configured to ensure it launches the matching activity correctly:

adb shell am start -a android.intent.action.VIEW -d <your_deep_link_url>

The final step for your migration will be to replace your published or shared Firebase Dynamic Links with App Links wherever possible, and to continue using App Links going forward.

Completing this step will vary depending on where and how you have your Firebase Dynamic Links published, but to help you track which ones exist, you can export your existing Firebase Dynamic Link metadata. See the Export Dynamic Links Metadata guide.

In order to use Universal Links, you must host a configuration file that helps establish a secure association between the domain used in your links and your app. For Universal Links, this is the apple-app-site-association file (also known as AASA file).

Steps to create and host the apple-app-site-association file

The AASA file allows us to provide a list of authorized apps that can handle the contents of the web domain we'll be using for our Universal Links. The AASA file itself needs to be hosted in the root of the web domain under the path: /.well-known.

Follow the steps below to complete this configuration:

  1. Create the ".well-known" folder under the public folder in your Firebase Hosting root directory.

  2. Create a file named "apple-app-site-association" under the ".well-known" folder.

  3. Copy the following content to your apple-app-site-association file, taking note of the meaning of each field below:

    {
      "applinks": {
        "apps": [],
        "details": [
          {
            "appId": "$TEAM_ID.com.firebase.UniversalLinks",
            "paths": [
              "NOT /_/*",
              "/*"
            ]
          }
        ]
      }
    }
    
    • $TEAM_ID.BundleId - the fully qualified application name authorized to handle the links
  4. Update your firebase.json file to index the file for hosting.

    "headers": [
      {
        "source": "/.well-known/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ]
    
  5. Now that we have the AASA file in place, do firebase deploy to host the changes.

  6. Verify the AASA file by going to https://your-project-domain.web.app/.well-known/app-app-site-association

In this step, you will recreate the deep-links from your Firebase Dynamic Links using regular deep-link URLs matching the new domain you've created for your Universal Links.

So for example, let's say you have the following Firebase Dynamic Link:

Dynamic Link Example
Link name Welcome to Example.com
Deep link https://example.web.app/welcome
Android app com.example.android
Apple app com.example.ios
Long Dynamic Link https://example.page.link/?link=https://example.web.app/welcome&apn=com.example.android&isi=123456789&ibi=com.example.iuos
Short Dynamic Link https://example.page.link/m9Mm

In this case, you would extract the deep link parameter - i.e.https://example.web.app/welcome and will now use this as the Universal Link parameter for your app.

You'll want to repeat this process for each Firebase Dynamic Link you wish to migrate to using App Links / Universal Links, and replicate the deep-linking schema you used.

For example, please see the following set of Firebase Dynamic Links short-links, deep link parameters and migrated deep link values:

Short link Deep link parameter Migrated deep link
yourapp.page.link/welcome https://example.com/welcome yourapp.web.app/welcome
yourapp.page.link/c7sn https://example.com/main/?p=23&t=1 yourapp.web.app/main/?p=23&t=1
yourapp.page.link/social https://example.com/friendinvite/?add=1 yourapp.web.app/friendinvite/?add=1

Next, you'll need to replace any instances of Firebase Dynamic Links that have been published or shared with the new migrated deep links so users will click on those Universal Links instead of the previous Firebase Dynamic Links.

The next step after selecting a domain, choosing a deep-linking schema and migrating your Firebase Dynamic Links to Universal Links is to update your iOS app and application code to receive the new deep links.

We recommend following the full Universal Links documentation here on configuring your app to handle deep links, but the main steps include:

  1. Update your project configuration to enable your app to handle deep links from your newly created domain

  2. Receive the deep link in your application code

In order to update your project configuration to enable your app to handle deep links, you'll need to add an additional Associated Domain to your project in xCode for the domain you're now planning to use to host your apple-app-site-associate file.

This can be done by:

  1. Opening Xcode
  2. Selecting your project in the file navigator
  3. Navigating to the Signing & Capabilities tab of your project settings
  4. Navigate down to the Associated Domains section
  5. Clicking on the + button to add the additional domain to your project in the format "applinks:".

Finally, you need to update your application code to be able to receive the incoming deep links.

To accomplish this, first update the AppDelegate.swift file to respond to a Universal Link by adding the following code:

func application(_ application: UIApplication, continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  AppDelegate.showReceivedUrl(userActivity: userActivity);
  return true
}

static func showReceivedUrl(userActivity: NSUserActivity) {
  if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
    let url = userActivity.webpageURL!
    print(url.absoluteString)
}

The above code overrides the Universal Link callback method and logs the deep link URL if present.

Now we will call the same showReceivedUrl method from the SceneDelegate class as well since if the app is already open by the time the user clicked on the universal link, the universal link callback inside SceneDelegate will be the one which gets invoked.

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
  AppDelegate.showReceivedUrl(userActivity: userActivity)
}

You can test the Universal Links you've just created by either running your app on a physical device or simulator.

You'll need to create a clickable link using the domain configured for your Universal Links and then click on that link to ensure that it opens up into your app and navigates you to the intended screen in your app.

Supporting Smart App Banners

We strongly recommend using Smart App Banners as a way to provide your users with a similar experience to Firebase Dynamic Links.

Using Smart App Banners, your users will be taken to the App Store for your app listing if your app isn't already installed on their device. You can also optionally configure a parameter to pass into your app after it gets downloaded and installed to provide your users with a continuation of their journey. If your app is already installed, it will open up passing in the parameter to your app to help navigate your user to the appropriate content based on the Smart App Banner that they clicked.

The final step for your migration will be to replace your published or shared Firebase Dynamic Links with Universal Links wherever possible, and to continue using Universal Links going forward.

Completing this step will vary depending on where and how you have your Firebase Dynamic Links published.

To help you track existing Firebase Dynamic Links to be migrated, we will be publishing a guide on how to export your short-link meta data from Firebase Dynamic Links. Please check back on our Dynamic Links Deprecation FAQ doc for more updates.