Give your simulator superpowers

RocketSim: An Essential Developer Tool
as recommended by Apple

Universal Links implementation on iOS

Universal Links allow you to link to content inside your app when a user opens a particular URL. Webpages will open in the app browser by default, but you can configure specific paths to open in your app if the user has it installed.

Redirecting users into your app is recommended to give them the most integrated mobile experience. A great example is the WeTransfer app that automatically opens transfer URLs, allowing the app to download the files using the most efficient system APIs. The alternative would require users to download the files via Safari, a much less integrated experience. Let’s dive in to see how you can add support for Universal Links.

Before we dive into Universal Links, it’s essential to understand the difference with deeplinks. Earlier, I explained how to set up and handle deeplinks in SwiftUI. The difference is best explained by looking at the URL format:

  • Deeplink: recipeapp://open-recipe?name=recipename
  • Universal Links: www.recipes.com/recipename

A deeplink uses a custom scheme with a path defining the action to execute. Universal Links are web URLs that open a web page if the app is not installed. In other words: deeplinks only work if the app exists, while universal links fall back to the web variant.

For the users, it’s a better experience to use Universal Links to ensure they’ll find what they’re looking for. If you cannot provide a web variant of the content you’re linking to, you can consider building an App Clip and reusing the code of your main app.

When users tap a universal link, the system redirects the link directly to your app without routing through Safari or your website. To make this work, you must establish a two-way connection between your app and domain. We do this by adding a so-called associated domain file to your website.

Adding an associated domain file to your website

An associated domain file contains information about your app and the domains your app supports. It’s checked by the system when users install your app to ensure URLs will open correctly. You secure the association of your app and website since you’re the only one able to store this file on your server.

You can find an example of such a file for my Stock Analyzer app: https://stock-analyzer.app/.well-known/apple-app-site-association. The file looks as follows:

{
    "applinks": {
        "details": [{
            "appIDs": ["4QMDKC8VLJ.com.swiftlee.StockAnalyzer"],
            "components": [{
                "/": "/stock/*",
                "comment": "Matches any URL whose path starts with /stock/"
            }]
        }]
    },
    "appclips": {
        "apps": [
            "4QMDKC8VLJ.com.swiftlee.StockAnalyzer.Clip"
        ]
    }
}

In this case, you can see that any URL containing the /stock/* path will open inside Stock Analyzer if the user has the app installed. The components array can be configured in several ways, for which Apple provides a few examples:

{
  "applinks": {
      "details": [
           {
             "appIDs": [ "ABCDE12345.com.example.app", "ABCDE12345.com.example.app2" ],
             "components": [
               {
                  "#": "no_universal_links",
                  "exclude": true,
                  "comment": "Matches any URL with a fragment that equals no_universal_links and instructs the system not to open it as a universal link."
               },
               {
                  "/": "/buy/*",
                  "comment": "Matches any URL with a path that starts with /buy/."
               },
               {
                  "/": "/help/website/*",
                  "exclude": true,
                  "comment": "Matches any URL with a path that starts with /help/website/ and instructs the system not to open it as a universal link."
               },
               {
                  "/": "/help/*",
                  "?": { "articleNumber": "????" },
                  "comment": "Matches any URL with a path that starts with /help/ and that has a query item with name 'articleNumber' and a value of exactly four characters."
               }
             ]
           }
       ]
   }
}

You can configure multiple application IDs that are formatted as follows:

<Application Identifier Prefix>.<Bundle Identifier>

The file must use the name apple-app-site-association (without extension), and you should upload it inside a folder called .well-known. Lastly, you must ensure the file uses https:// with a valid certificate and no redirects.

Associating your app with your domain

You can associate your app with your domain by adding the Associated Domains Entitlement by tapping the + Capability button in Xcode:

Add the Associated Domain entitlement in Xcode to support Universal Links.
Add the Associated Domain entitlement in Xcode to support Universal Links.

Once added, you can start configure entries for each domain you want to support:

An example of a Universal Links configuration for Stock Analyzer.
An example of a Universal Links configuration for Stock Analyzer.

My Stock Analyzer app supports only a single domain for Universal Links (applinks:) and App Clips (appclips:). You must ensure having an entry for each domain-associated file entry.

Handling subdomains

Your site could support multiple subdomains like example.com and www.example.com. Adding an entry for each domain inside the associated domain file and app entitlement is essential in this case.

Stay updated with the latest in SwiftUI

Join 20,020 Swift developers in our exclusive newsletter for the latest insights, tips, and updates. Don't miss out – join today!

You can always unsubscribe, no hard feelings.

You can handle Universal Links inside your app by adding the openURL modifier inside SwiftUI views or implementing a specific AppDelegate method. You can follow the configuration section of my deeplinks article for more details.

After configuring both domain and app-associated domains, testing your implementation is essential. I recommend using RocketSim for testing both deeplinks and Universal Links, as you can access them right next to the simulator.

After installing RocketSim, you can open its Settings window and add a new Deeplinks Group:

Add a new Deeplink group inside RocketSim and configure your bundle identifier.
Add a new Deeplink group inside RocketSim and configure your bundle identifier.

Configuring your bundle identifier to match your app is essential, so quick actions appear inside RocketSim’s Recent Builds section (I’ll show that later). Secondly, you need to add a new Universal Link using the “Add” button in the bottom-right corner:

Configure the Universal Links to test inside RocketSim.
Configure the Universal Links to test inside RocketSim.

Once you’ve created a group with Universal Links and matching bundle identifier, you can start accessing URLs directly next to the Simulator:

Universal Links show up next to the Simulator inside RocketSim.
Universal Links show up next to the Simulator inside RocketSim.

You’ll now only have to tap the quick action button to open the URL inside your app. RocketSim is excellent for these cases and allows you to do the same for testing locations, push notifications, or Airplane Mode.

Conclusion

You can use Universal Links to create an integrated user experience by opening web URLs directly in your app. Unlike deeplinks, users will be redirected to a web page if the app isn’t installed. An entitlement inside your app combined with a domain-associated file secure a relationship between your site and app.

If you want to improve your SwiftUI knowledge, even more, check out the SwiftUI category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.

Thanks!

 
Antoine van der Lee

Written by

Antoine van der Lee

iOS Developer since 2010, former Staff iOS Engineer at WeTransfer and currently full-time Indie Developer & Founder at SwiftLee. Writing a new blog post every week related to Swift, iOS and Xcode. Regular speaker and workshop host.

Are you ready to

Turn your side projects into independence?

Learn my proven steps to transform your passion into profit.