Universal Links is a great feature that allows us to render content in an app when a user hits a known URL, instead of opening Safari. For content-based applications, this can be especially useful, as often records that exist on the web also exist in the app. We'll leverage our work from Episode 231 on Shared Web Credentials and extend the demo app to take advantage of Universal Links.
Episode Links Source Code Adding Universal Links Support First, we need to add the appropriate entitlement. We can do this on the Capabilities tab in the project's settings. We'll define a new Associated Domain, with a value of: applinks:desolate-springs-88496.herokuapp.com Next, we need to update our server. We'll modify the response for /apple-app-site-association to include a new applinks section: get '/apple-app-site-association' do content_type 'application/json' { "webcredentials": { "apps": [ "C2K3864N2N.com.nsscreencast.SharedWebCredentialsDemo" ] }, "applinks": { "apps": [], "details": [ { "appID": "C2K3864N2N.com.nsscreencast.SharedWebCredentialsDemo", "paths": ["/episodes", "/episodes/*"] } ] } }.to_json end Note that the apps key must be an empty array, according to the docs. Handling Universal Link Taps Now we need to open our AppDelegate and handle the case when a user taps on a universal link. To do this, we leverage the Handoff API, specifically the application:continueUserActivity:restorationHandler: method: func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool { // verify that this is the right activity type, we have a valid URL guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL, let path = url.path else { return false } // try to match the path part of the URL to our content. // here we're using a statically defined array of episodes as our source. // this could be Core Data, or however you have your data stored. if let match = SampleEpisodes.filter({ $0.path == path }).first { let episodeVC = EpisodeViewController(episode: match) let episodesRoot = EpisodesViewController() let nav = UINavigationController() nav.viewControllers = [episodesRoot, episodeVC] window?.rootViewController?.presentViewController(nav, animated: true, completion: nil) return true } // if we can't handle it, default to open the URL in Safari application.openURL(url) return false }