Topics

#91: Universal Links πŸŒŽπŸ”—

Topics

Universal Links arrived with iOS 9. Conceptually they're a way for us to logically tie the content in our app to the content on our website. Once this is done, iOS will be able to launch our app when a user taps a link somewhere, rather than opening our site in Safari. Let's take a further look by adding Universal Links to a fictional Little Bites of Cocoa app. We'll start by registering and setting up SSL for our domain: littlebitesofcocoa.com.

Then, we'll head into Xcode and to the Capabilities tab of our project. We'll flip on the switch for Associated Domains, then click the + button and add our domain. Note that we prefix it with the phrase applinks:.

Now, our app will silently make an HTTP GET request to
https://littlebitesofcocoa.com/apple-app-site-association.

It will expect us to return some JSON which describes our app's Bundle ID, and which paths should open it.

We'll open all paths on our domain using a wildcard character here, but we could easily, for example, limit to just Bite URLs.

{
  "applinks": {
    "apps": [],
    "details": {
      "TEAMIDHERE.com.magnus.lboc": {
        "paths": [ "*" ]
      }
    }
  }
}

After creating the file, we'll need to sign it so it is returned with a Content-Type of application/pkcs7-mime on our server. We'll use a command like the one shown here to sign the file. (This part stinks, but there's no way around it).

cat aasa.json | openssl smime -sign
                              -inkey littlebitesofcocoa.com.key
                              -signer littlebitesofcocoa.com.pem
                              -certfile intermediate.pem
                              -noattr
                              -nodetach
                              -outform DER > apple-app-site-association

Lastly, we'll wire up the other side of the equation. When a user opens a Universal Link that iOS recognizes, it will call the same delegate function that's used to implement features like Handoff (Bite #29) and Spotlight Search (Bite #23). We'll check if it's a Universal Links activity type, then use JLRoutes (Bite #62) to open a section of our app.

extension AppDelegate {
  func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {

    if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
      return JLRoutes.routeURL(userActivity.webpageURL!)
    }

    return true
  }
}