Universal Links – Make the Connection

Owen Brown
Universal Links

Connecting Apps and Websites

Update 10/01/2016: Updated for Xcode 8 / Swift 3.

Do you have a website that shares content with an iOS app? As of iOS 9, you can connect them using universal links, meaning that users can now touch an HTTP link on an iPhone and be sent directly to your app!

In this tutorial, you’ll learn how to link an iOS app to a Heroku website. Both the app and website provide reference material for single board computers, so hardware-hobbyist freaks, rejoice! You’re in for a treat. :]

This tutorial assumes you have a basic understanding of Swift and iOS development. If you’re new to these, go through some of our other tutorials on Swift and iOS development first. Previous experience with Heroku and web development would be beneficial, but isn’t strictly required.

Lastly, you must have a paid Apple developer account. A free account won’t work, unfortunately.

Note: Universal links are in many ways a replacement for apps registering their own URL schemes. They work by providing a small file (served over HTTPS) from the root of a web domain that points to a specific app ID, and by that specific app ID being registered with Apple as handling links from that domain.

Because of these requirements, you won’t be able to fully try out universal links without having a real website accessible via HTTPS and a real app on the App Store, but you can still gain experience with universal links by going through the process of setting everything up.

Getting Started

Download the starter project here. Build and run, and you’ll see the app’s main view controller, ComputersController.

UniversalLinks - Main View

Main View

The app shows a few of the most popular single board computers on the market. Touch one of the rows to segue to the details view controller, ComputerDetailController. Here you can see product-specific information, including the website, vendor, and pricing.

UniversalLinks - Navigating

Navigating the Views

A basic website with similar information has also been created. Check out the starter website here.

Single Board Computer's Website

Single Board Computers Website

Don’t fret the Heroku part: it’s just a quick way for you to access the demo website for the tutorial. Though not required by this tutorial, you may optionally deploy the website to your own Heroku account. If you want to do so, follow the instructions here.

Now that you’ve seen both the app and the website, it’s time to dive into the code to connect them. The end goal: whenever a user taps any of your website links on an iOS device—such as https://rw-universal-links-starter.herokuapp.com/arduino.html—it will be opened by the app, instead of Safari. As a final bit of polish, the app will even navigate directly to the specific computer detail controller.

To accomplish this, you need to do three things:

  1. Inform the app of the website.
  2. Inform the website of the app.
  3. Handle navigation within the app whenever a link is tapped.

There are a couple requirements for creating universal links. First, you must have “write access” to the linked website, which must use HTTPS, and you must be able to upload a file to it. Second, you must own the associated app, so you can edit its provisioning profile “capabilities” to register the website and be able to deploy it to the App Store.

For these reasons, you won’t be able to test the tutorial app. However, you’ll still go through the process to learn how it’s done.

Configuring the App

You first need to configure the app to handle universal links. Open the UniversalLinks.xcodeproj from the Starter folder and do the following:

  1. Select the UniversalLinks project.
  2. Select the UniversalLinks target.
  3. Select the Capabilities tab.
  4. Scroll to and turn ON Associated Domains.
Turn On Capabilities

Turn On Capabilities

You may get a prompt to Select a Development Team to Use for Provisioning. Select any paid Apple developer team that you’re on and press Choose to continue.

If you see a prompt to Add an Apple ID Account, it means you’re not currently signed into any accounts. In this case, press the Add button and sign into a paid Apple developer team of which you’re a member.

It’s important that this be a paid account. When I tried to use a free account in my testing, Xcode consistently crashed; this appears to be an Xcode bug.

You’ll also see a error message saying “An App ID with identifier ‘com.razeware.UniversalLinks’ is not available”. This is because the app identifier is already taken by the original tutorial app.

In your own app, make sure your app identifier is unique (following reverse domain name notation). For this tutorial app, however, it’s okay to simply ignore this message. ;]

Next, press + and add the following domain:
applinks:rw-universal-links-final.herokuapp.com

Be sure to add the applinks prefix. You should now see the following:

Associated Domains

Associated Domains

The first step is complete! The app is now aware of the website’s URL. Next, you’ll configure the website.

Configuring the Website

Now you need to let the website in on the “big secret.” To do this, create an apple-app-site-association file. This file isn’t new to the iOS world: it’s the same file used in iOS 8 for web credentials and Handoff. The format matches that of a JSON file, but it CANNOT have the .json extension. No extension should be used, and to preserve your debugging sanity, double-check that the file name matches exactly!

Rage_AppleFile

Create the apple-app-site-association file and add the following content:

{
  "applinks": {
    "apps": [],
    "details": [
    {
      "appID": "KFCNEC27GU.com.razeware.UniveralLinksTutorial",
      "paths": ["*"]
    }
    ]
  }
}

The applinks tag determines which apps are associated with the website. Leave the apps value as an empty array. Inside the details tag is an array of dictionaries for linking appIDs and URL paths. For simplicity, the “*” wildcard character is used to associate all of this website’s links with the UniversalLinks app. Additionally, the paths value can be limited to specific folders or file names.

The appID consists of your team ID combined with the app’s bundle ID. The team ID listed above belongs to the Ray Wenderlich team, but you’ll need to use the identifier for your own account.

Apple assigned you a team ID when creating your Apple developer account. It can be found in the Apple developer center. Log into the website, click on the Your Account tab and scroll down to the Developer Account Summary section. You will find your team ID there.

Developer Account Summary

Developer Account Summary

You can find the app’s bundle ID via Xcode’s Targets\UniversalLinks\General tab:

Bundle ID

Now that the apple-app-site-association is complete, it’s time to upload it to the web server.

Again, you must have “write access” to the website to do this. For the sake of the tutorial, you can refer to the finished website, which already contains this file.

If you want to ensure it is there, open http://rw-universal-links-final.herokuapp.com/apple-app-site-association. You’ll see that it matches the info shown above.

Great! The app knows about the website, and the website knows about the UniversalLinks app. It’s time for the final step: adding app logic to handle when a universal link is tapped.

Handling Universal Links

Now that the app and the website are officially aware of each other, all the app needs is code to handle the link when it’s called.

Open AppDelegate.swift and add the following helper method:

func presentDetailViewController(_ computer: Computer) {
    
  let storyboard = UIStoryboard(name: "Main", bundle: nil)
    
  let detailVC = storyboard.instantiateViewController(withIdentifier: "NavigationController")
      as! ComputerDetailController
  detailVC.item = computer
    
  let navigationVC = storyboard.instantiateViewController(withIdentifier: "DetailController")
      as! UINavigationController
  navigationVC.modalPresentationStyle = .formSheet
    
  navigationVC.pushViewController(detailVC, animated: true)
}

This method opens the ComputerDetailController and displays the Computer parameter’s information. This provides you with a clean way of navigating to a specific single board computer. You’ll use this method next.

Right after the previous method, add the following delegate method:

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 let computer = ItemHandler.sharedInstance.items.filter({ $0.path == components.path}).first {
    self.presentDetailViewController(computer)
    return true
  }
    
  // 3
  let webpageUrl = URL(string: "http://rw-universal-links-final.herokuapp.com")!
  application.openURL(webpageUrl)
    
  return false
}

This method is called whenever a universal link related to the app is tapped. Here’s what each step does:

  1. First, you verify that the passed-in userActivity has expected characteristics. Ultimately, you want to get the path component for the activity. Otherwise, you return false to indicate that the app can’t handle the activity.
  2. Using the path, you look for a known computer that matches it. If one is found, you present the detail view controller for it and return true.
  3. If no computer that matches the path is found, you instruct the application to open the URL, which will use the default system app instead—most likely Safari. You also return false here, to indicate that the app can’t handle the user activity.

Testing the Links

As discussed above, there isn’t a great way to test whether the universal links work in the tutorial app, but it’s important to understand the expected outcome for when you implement universal links in your own applications.

If you had implemented this in your own app, you would be able to e-mail yourself a link (e.g. https://rw-universal-links-final.herokuapp.com/arduino.html), tap it, and verify that the correct page is shown.

Remember that universal links can be triggered from other places as well, such as within a UIWebView, WKWebView, SFSafariViewController, Notes or directly within Safari.

Where to Go From Here?

Here is the tutorial’s finished sample project, and you’ll find the finished website here: https://rw-universal-links-final.herokuapp.com.

Congratulations! You’ve learned a lot about how to implement universal links in iOS. You’re now ready to apply this concept to your own app and create “real” universal links—you can do it!

Want to dig deeper into this topic? Check out the section on universal links (Chapter 3) in iOS 9 by Tutorials.

You can find additional reference material directly from Apple’s documentation.

To test out your implementation of universal links on your own website, you can use this tool or Apple’s own link validator, both of which can point out possible problems in your setup.

If you have questions or comments, feel free to jump into the forum below and ask away!

Owen L Brown

Owen is a software engineer with a strong background in mechanical and electrical design. He has 17+ years of experience in writing embedded microcontroller firmware for machine automation. For the last several years, he has focused on integrating machine control with iOS using Bluetooth. He has several cool machine-control Bluetooth LE applications on the app store. Owen is also the author of a book called 'Integrating iOS Bluetooth LE with PIC18 Microcontrollers'. He can be reach via email. Feel free to checkout his website at Back-40.com.

Other Items of Interest

Save time.
Learn more with our video courses.

raywenderlich.com Weekly

Sign up to receive the latest tutorials from raywenderlich.com each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 20 total!

Swift Team

... 15 total!

iOS Team

... 44 total!

Android Team

... 15 total!

macOS Team

... 11 total!

Unity Team

... 11 total!

Articles Team

... 15 total!

Resident Authors Team

... 17 total!

Podcast Team

... 8 total!

Recruitment Team

... 9 total!