Getting deeper with deep linking on iOS

Azzaro Mujic
Undabot
Published in
7 min readFeb 22, 2017

If you have a website that allows users to access some of the same content and functionality as your app, this post is for you. As of iOS9 it is possible to connect websites and iOS apps using universal links. In other words, when users click on HTTP/HTTPS link on an iPhone or iPad they will be redirected to an iOS app!

In this post you will learn how to link iOS apps with websites, you will learn how linking works under the hood and you will also learn how to test the link without having your own website.

The Fall of URI Schemes and the Rise of Universal Links

Before universal links iOS apps used to implement a custom URL scheme to communicate with each other. This is an efficient tool tool, but it does have a few pitfalls.

  • URL schemes don’t always map to the right app, because there is no app that truly owns them
  • two apps can claim the same URL scheme and users aren’t offered an effective way to choose which app they want to open
  • if the app you want to open with an URL is not installed then you need custom code to handle situation
  • they make protecting the user’s privacy difficult

On the other hand, universal links provide a strong two-way association between your app and your URLs. If you don’t have the app installed URLs will still work and they will open Safari, and on top of everything, it absolutely protects user’s privacy.

How it works

Universal links work by providing a configuration file served over HTTPS from the root of a web domain. That file specifies app IDs registered with Apple as handling links from that domain.

What do you need

First off you need a paid Apple developer account and website accessible via HTTPS. If you don’t have a website it is possible to test without it using a trick that I will describe later.

How to make it happen (step by step)

Prepare the app

  1. enable Associated Domains on Apple’s Developer Center
  2. generate your provisioning files for your app, download them and install them on Xcode.

Configure the app

  1. Go to Xcode and select your app target.
  2. In the Capabilities section, enable Associate Domains.
  3. Add your domain. Note: The domain has to be prefixed by applinks, for example: applinks:mydomain.com

applinks:mydomain.com and applinks:www.mydomain.com are different domains

Configure the website

Upload your JSON file with an apple-app site-association name to your HTTPS server. More precisely, url: https://mydomain.com/apple-app-site-association should have a JSON response like this:

{
"applinks": {
"apps": [],
"details": [
{
"appID": "KLD9S9KY48.com.deeplinking.test",
"paths": [
"/path1/1234567",
"/path2/*",
"NOT /path2/2014/*",
"/path3/201?/mypage"
]
}
]
}
}

The top level key is applinks and it describes the feature that we want to use. The apps key, according to documentation, should be always present with an empty array as its value. There is no specific reason why it should be like that. The details key should contain dictionaries - one dictionary per website supported app. Those dictionaries have an appID which represents the application identifier. The value of the appID key is the team ID or app ID prefix, followed by the bundle ID. The value of the paths key is an array of strings that specify the parts of your website that are supported by the app and the parts of your website that you don’t want to associate with the app.

There are various ways to specify website paths:

  • use * to specify your entire website
  • include a specific URL, such as /path1/1234567, to specify a particular link
  • append * to a specific URL, such as /path2/*, to specify a section of your website
  • use ? to match any single character, /path3/201?/mypage
  • use NOT to specify an area that should not be handled as an universal link, such as NOT /path2/2014/*

The strings you use to specify website paths in the paths array are case sensitive.

Here you can see a real worldwide example that has two apps registered, one for debugging purposes and one for live production.

Handling Universal Links

In AppDelegate implement a function for handling universal links, specifically application:continueUserActivity:restorationHandler.

When iOS launches your app after a user taps a universal link, application:continueUserActivity:restorationHandler function is called in AppDelegate. In that function you receive an NSUserActivity object with an activityType value NSUserActivityTypeBroswingWeb. The activity object's webpageURL property contains the URL that the user is accessing. The webpage URL always contains a HTTP or HTTPS URL and you can use the NSURLComponents API to handle URL components.

Here is an example.

func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([Any]?) -> Void) -> Bool {

// 1
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL,
let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
return false
}

// 2
if components.path == "path1",
components.query == "1234567" {
// open screen for path: /path1/1234567
return true
} else if components.path == "path2" {
// open screen for path: /path2/*
return true
}

// 3
application.openURL(url)

return false
}

This function is called whenever a universal link opens your app. Below is a list of steps:

  • First, you need to verify that the passed-in user-activity has the expected characteristics.
  • After that, you should try to handle the passed url.
  • If your application does not support the passed url you can opt to show an error message to the user or you can call the function openURL: to open the passed URL link in Safari. It’s important to understand that if your app uses openURL: to open an universal link to your website, the link does not open in your app. In this scenario, iOS knows that the call originates from your app and therefore should not be handled as a universal link by your app.

To protect users’ privacy and security, you should not use HTTP when you need to transport data; instead, use a secure transport protocol such as HTTPS.

Testing

Many tutorials will say that a good way to test universal links doesn’t exist. One way is to have your website accessible via HTTPS, but what if you don't have a website or if you just work on iOS applications and do not have the access needed to modify API?

I have found a great solution for testing universal links, as it is a very easy and elegant solution. Instead of configuring your website you can create an account on mockable.io and configure the endpoint with path /apple-app-site-association to allow it to return an appropriate JSON response.

Once you have completed all of the above steps, you can test universal links by e-mailing yourself a link, tapping it, and verifying that the correct screen is shown in your app.

To test out your implementation of universal links on your own website, you can use Apple’s link validator.

Universal links can be triggered from other places as well, such as within a UIWebView, WKWebView, SFSafariViewController, Notes, Messages, Viber, WhatsApp, Facebook or directly within Safari.

What if I want to open link in Safari even if I have the app installed

If you have the corresponding app, the link will be opened in the native app by default. However, users can always switch between the native app and Safari.

When the native app is opened via universal link, users can tap a breadcrumb button in the status bar to open the link in Safari. If the link is opened with Safari, the user will be able to switch to the native app by tapping OPEN in the Smart App Banner on the webpage.

Where to go from here

You can find additional reference material directly from Apple’s documentation or you can watch Seamless Linking to Your App video from WWDC.

If you want to try out advanced things like supporting multiple operating systems or opening App Store or Google Play if the user doesn’t have the app installed and leading him to the specific “deferred” content immediately after first launch, I recommend you to check branch.io.

Thank you for reading and feel free to post questions and comments below.

Thanks to Sinisa Cvahte for the design.

Thank you for reading. Please comment, like or share it with your friends and we hope to see you soon.

Would you like to join us? Check out the open positions at our Careers page.

Undabot and Trikoder are partner organisations. We analyze, strategize, design, code and develop native mobile apps and complex web systems.

--

--