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
}
}