iOS Life

  • Home
  • ABOUT
  • SERVICES
  • PORTFOLIO
  • BLOG
  • Contact

Tutorial: Deep Linking in Swift

Deep Linking is becoming very important in apps these days. You can deep link from another app or even from a website to your app. If you want to direct a user to relevant content and they already have your app, linking to a specific article or an app section from an ad, promotion, or your website makes things a lot easier for them.

Register your URL Scheme

A URL scheme lets you communicate with other apps through a protocol that you define. To communicate with an app that implements such a scheme, you must create an appropriately formatted URL and ask the system to open it. To implement support for a custom scheme, you must declare support for the scheme and handle incoming URLs that use the scheme.

Similar to a URL “http://”, ours for the app is going to be set to “DeepLink://”. You can set this to whatever you like but make sure it is unique as possible, no other app on the users phone should have the same URL scheme.

To register your URL Scheme add the following fields to your Info.plist. Add URL Types, then within Item 0, set Document Role to Editor. URL Identifier to your app bundle ID. Create a URL Schemes field and set Item 0 to the URL Scheme you want to use, i.e. “DeepLink” (don’t put in the protocol symbols ://)

Screen Shot 2015-07-12 at 3.19.09 PM

Handling URL Requests

app_bg_open_url_2x

An app that has its own custom URL scheme must be able to handle URLs passed to it. All URLs are passed to your app delegate, either at launch time or while your app is running or in the background. To handle incoming URLs, your delegate should implement the following methods below.

The sample URL being loaded is DeepLink://article/A. Below we are looking to see if the deep link type is an article. You may have videos, show, app section in your app.

var window: UIWindow?
var loadedEnoughToDeepLink : Bool = false
var deepLink : RemoteNotificationDeepLink?

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
    
    if url.host == nil
    {
        return true;
    }
    
    let urlString = url.absoluteString
    let queryArray = urlString!.componentsSeparatedByString("/")
    let query = queryArray[2]
    
    // Check if article
    if query.rangeOfString("article") != nil
    {
        let data = urlString!.componentsSeparatedByString("/")
        if data.count >= 3
        {
            let parameter = data[3]
            let userInfo = [RemoteNotificationDeepLinkAppSectionKey : parameter ]
            self.applicationHandleRemoteNotification(application, didReceiveRemoteNotification: userInfo)
        }
    }
    
    return true
}

func applicationHandleRemoteNotification(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
{
    if application.applicationState == UIApplicationState.Background || application.applicationState == UIApplicationState.Inactive
    {
        var canDoNow = loadedEnoughToDeepLink
        
        self.deepLink = RemoteNotificationDeepLink.create(userInfo)
        
        if canDoNow
        {
            self.triggerDeepLinkIfPresent()
        }
    }
}

func triggerDeepLinkIfPresent() -> Bool
{
    self.loadedEnoughToDeepLink = true
    var ret = (self.deepLink?.trigger() != nil)
    self.deepLink = nil
    return ret
}

If your app is not running when a URL request arrives, it is launched and moved to the foreground so that it can open the URL. We call applicationHandleRemoteNotification and initialize our custom Deep Link Handler class RemoteNotificationDeepLink to store the userInfo and we’ll call triggerDeepLinkIfPresent() in our main ViewController once it’s loaded to grab the data.

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    appDelegate.triggerDeepLinkIfPresent()
}

Next we trigger our custom Deep Link Handler class to take the parameters in the url “DeepLink://article/A” to handle what article A is and open that ViewController in your app to complete the deep link.

//
//  RemoteNotificationDeepLink.swift
//  DeepLink
//
//  Created by Brian Coleman on 2015-07-12.
//  Copyright (c) 2015 Brian Coleman. All rights reserved.
//

import UIKit

let RemoteNotificationDeepLinkAppSectionKey : String = "article"

class RemoteNotificationDeepLink: NSObject {
   
    var article : String = ""
    
    class func create(userInfo : [NSObject : AnyObject]) -> RemoteNotificationDeepLink?
    {
        let info = userInfo as NSDictionary
        
        var articleID = info.objectForKey(RemoteNotificationDeepLinkAppSectionKey) as! String
        
        var ret : RemoteNotificationDeepLink? = nil
        if !articleID.isEmpty
        {
            ret = RemoteNotificationDeepLinkArticle(articleStr: articleID)
        }
        return ret
    }
    
    private override init()
    {
        self.article = ""
        super.init()
    }
    
    private init(articleStr: String)
    {
        self.article = articleStr
        super.init()
    }
    
    final func trigger()
    {
        dispatch_async(dispatch_get_main_queue())
            {
                //NSLog("Triggering Deep Link - %@", self)
                self.triggerImp()
                    { (passedData) in
                        // do nothing
                }
        }
    }
    
    private func triggerImp(completion: ((AnyObject?)->(Void)))
    {
        
        completion(nil)
    }
}

class RemoteNotificationDeepLinkArticle : RemoteNotificationDeepLink
{
    var articleID : String!
    
    override init(articleStr: String)
    {
        self.articleID = articleStr
        super.init(articleStr: articleStr)
    }
    
    private override func triggerImp(completion: ((AnyObject?)->(Void)))
    {
        super.triggerImp()
            { (passedData) in
                
                var vc = UIViewController()
                
                // Handle Deep Link Data to present the Article passed through
                
                if self.articleID == "A"
                {
                    vc = ViewControllerA()
                }
                else if self.articleID == "B"
                {
                    vc = ViewControllerB()
                }
                else if self.articleID == "C"
                {
                    vc = ViewControllerC()
                }
                
                let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
                appDelegate.window?.addSubview(vc.view)
                
                completion(nil)
        }
    }
    
}

Testing the Deep Link

To make sure that the deep links are working put the links onto a website and view it in Safari.

First run the app in the Simulator, in our app you’ll just see a blank page, but the app has been initialized and is ready to handle the URL.

Next press the phone Home button or in the Simulator Hardware > Home. It will take you out of the app. Launch Safari and put in this URL: http://www.brianjcoleman.com/code/deepLinkTest.html.

deepLinkTest.html




DeepLink://article/A

DeepLink://article/B

DeepLink://article/C

You’ll see there links, each that link to a different article A, B, or C.

Select one of the links and watch as the app opens and links right to the article chosen.

Screen Shot 2015-07-12 at 10.00.40 PM

Detect If Your App is Installed

Below is a little bit of JavaScript that you can add to your website to detect if the user has your app installed. If they don’t you can redirect the user to the App Store to download your app. If they do have it you can deep link directly into your app.





You can grab the
full source code for this tutorial. Note: Created using XCode 6.4 (Swift 1.2).

Jul 13, 2015 Brian Coleman
Tutorial: Receipt Validation in SwifttvOS Tutorial: Make a Video App in Swift
You Might Also Like
 
Tutorial: Setting up a Jenkins Automated Build Server for iOS
 
Tutorial: Designing and Exporting Your App Icon
7 years ago Swift, Tutorialsios8, swift, tutorial70,909
Follow Me
    
Categories
  • About Me
  • Frameworks
  • My Apps
  • News
  • Strategy
  • Swift
  • Tools
  • Tutorials
  • tvOS
  • Uncategorized
  • Videos
  • Watch
Archives
  • May 2016
  • January 2016
  • October 2015
  • July 2015
  • May 2015
  • April 2015
  • March 2015
  • November 2014
  • October 2014
  • September 2014
  • July 2014
  • June 2014
  • September 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
brianjcoleman on Twitter
  • Classix is still holding in the top charts on Apple TV in Canada. #55 Free, #23 Top Grossing. #tvos #appletv #app https://t.co/xuEJiT4rro, Jul 14
  • New Blog Post: "Classix for iPhone, iPad & Apple TV” #iOSDev #ios #swift #swiftlang #SwiftDevs #AppleTV Read here: https://t.co/uF6w3gYOot, May 20
  • New Blog Post: "How to test your app for IPv6 compatibility” #iOSDev #ios #swift #swiftlang #SwiftDevs Read here: https://t.co/SveichSUep, May 6

Recent Posts
  • Classix for iPhone, iPad & Apple TV
  • Tutorial: How to test your app for IPv6 compatibility
  • Tutorial: Testing SSL using Charles Proxy on an iOS Device
  • Tutorial: 3D Touch – Quick Actions in Swift
  • tvOS Tutorial: Top Shelf in Swift
Featured Apps
Classix
Sportsnet
TAGS
tutorialswiftios8iosobjective-cvideostrategygamesframeworknewsappsmonitizeios7applefacebookwatchtoolstvosios9bookdesignsocialapiprovisiontutorialsbooksiapiTunes ConnectIPv6
Search
ABOUT
Brian is a Lead iOS/tvOS Developer from Toronto with over 18 years of multifaceted experience including development, design, business analysis and project management.
MOST VIEWED
Tutorial: How To Use Login in Facebook SDK 4.1.x for Swift
163,489 views
Tutorial: How to test your app for IPv6 compatibility
102,074 views
Tutorial: How to use Auto Layout in Xcode 6
89,234 views
FOLLOW ME
    
Email Subscription
Sign up for my newsletter to receive the latest news and tutorials posted.

Enter your email address:

2013-2017 © Brian Coleman