David Yang

Tips and posts for iOS developers from an iOS developer.

Universal Links is a feature allowing redirection to your mobile app. Its main goal is to offer the end user the ability to display your content either on your mobile app (if it is installed) or your website.

To illustrate the benefits, let’s have a look on the Google Maps app.

With the app installed, the first time you’ll try to open a Google Maps link, the system will prompt you by asking if you would like to open it with the app. By accepting, the system will save that preference and open all future and similar links with the app, offering a richer experience.

But the user can always chose to open the link with the default behavior, opening Safari, by a long-tap gesture on the link. Doing so will also save that new preference in the system.

By definition, Universal Link also offers a similar feature as URL schemes: it can open a mobile app and provide parameters to it in the form of a URL link. Universal Link is safer than URL schemes though, making it the preferred way to invoke an app nowadays.

Unfortunately, safety comes with a price: a website.

Implementation

On the website

In order to implement Universal Links, a secure website is mandatory (https).

The following content have to be served and available at this path: https://[Your_Domain]/.well-known/apple-app-site-association.

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "YOUR_TEAM_ID.fr.y4ng.sampleApp",
				"paths": [
				    "/profile/settings/",
					"/articles/*"
				]
            },
            {
                "appID": "ABCD1234.fr.y4ng.movieBang",
				"paths": [ "NOT /profile/*", "*" ]
            }
        ]
    }
}

Under the paths array, you can provide the list of paths you want (or explicitly not) to be handled by your app.

On your app

First, make sure you enabled the Associated Domain entitlements on your App ID configuration.

Then, add the following in your com.apple.developer.associated-domains entitlement: applinks:myapp.y4ng.fr.

Finally, implement the following method in your AppDelegate:

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL {
		// Handle the URL here
        print(url.absoluteString)
    }
    return true
}

Validation

In order to check your website configuration, you can use some of the following online tools:

Note: From my experience, for Universal Link only implementation, some of the checks are not mandatory to make it work, espacially the content-type header. But please note that Associated Domains is not limited to Universal Links. It also enables services such as App Clips and Web Credentials, for which those specific checks may be required.

How does it work?

Once everything is setup, here’s how it will work on your devices running iOS 14+.

  • After your app installation, the device will request through Apple managed content delivery network (CDN) the apple-app-site-association for the domain provided by your Associated Domain entitlement.
    • If the CDN has anything about your Associated Domain, the content will be provided to your device.
    • If not, the CDN will request the apple-app-site-association hosted on your website and cache it.
  • Any URL matching the paths and domains provided in your apple-app-site-association will be opened by the app its matching App ID.

Note:

With the CDN in the middle, be aware that any changes on your apple-app-site-association file may require 48h until it is updated on the CDN.

For devices running iOS versions prior to 14, no CDN are used. Instead, the device will directly require the apple-app-site-association hosted on your website and cache it locally.

Development tips

The 48 hours delay for the update of your apple-app-site-association file on the Apple managed CDN is not suitable for development purposes.

This behavior can be overriden in order to bypass the CDN. To do so:

  • Enable Associated Domain Development on your device (go to Settings > Developer)
  • Use the developer mode in your Associated Domain entitlements by setting the mode parameter: applinks:myapp.y4ng.fr?mode=developer

Still running issues?

Debugging a Universal Link setup is challenging…

As an additional tip, you can try using the Console app available on macOS in order to view your device’s logs. You can then filter the logs: the ones you will be interested in are from the swcd process.

Here for example, I ran into issues due to a 403 error response sent from my website to the Apple managed CDN dedicated to Associated Domain.

universal-link-console-logs

You can also have a look at what’s on the apple-app-site-association cached by Apple’s CDN by requesting the following file:

https://app-site-association.cdn-apple.com/a/v1/[Your-Domain]
// example: https://app-site-association.cdn-apple.com/a/v1/google.com