Deep Linking with Universal Links on
All Platforms

Deep Linking with Universal Links

This guide will walk you through setting up deep linking with Universal Links using DeepLink Kit - the most popular open-source library for deep link routing.

Universal Links

Universal Links allow you to open your app to specific content or actions from an http-style URL, if your app is installed. This means that for any given web URL, it will open in your app if it's available, or on the website if not. It is the simplest way to support deep linking and is the method that both Google and Apple now recommend.

e.g. https://resy.com/cities/ny/charlie-bird will open in the Resy App if you have it installed, or on the web otherwise.

Steps

This guide will walk through three steps to get Universal Links up and running in no time.

  1. Setup the 'Associated Domains' app Entitlement
  2. Configure your web domain to trust your app
  3. Route incoming Universal Links in your app

Setup Entitlements

The first step is to configure your app to support Universal Links - this is done through entitlements in the Capabilities tab.

Navigate to your project and select your app's main target.

From there select Capabilities from the top tab bar and enable the Associated Domains capability.

<

Add your domain to this list in the format applinks:yourdomain.com.

Once you add your domain, you may see a button appear below that reads Fix Issue. If you do, tap it. This will configure your App ID in the Apple Developer Center with this entitlement & regenerate your Provisioning Profiles.

Note: If you manage your App & Provisioning Profiles manually, you will need to enable the Associated Domains entitlement on your App ID in the Apple Developer Console and then regenerate any Provisioning Profiles.

Configure your Domain

Before your Universal Links will be able to open your app, we need to configure the web domain registered above to allow the app to handle it's URLs. This is a security feature that forms a 'trust' relationship between the app and domain to ensure that not just anybody can redirect your traffic to their app.

This trust is established by simply placing a file called the apple-app-site-association file at the root of your domain.

This file should look like this:

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "YOUR_TEAM_PREFIX.com.usebutton.your_app_bundle_identifier",
        "paths": [
          "*"
        ]
      }
    ]
  }
}

This should be accessible at https://YOUR-DOMAIN.com/apple-app-site-association. You can test whether your Universal Links association is working correctly using Apple's [AppSearch Validator Tool.

Some notable requirements:

    • The apple-app-site-association file must be accessible over https with a valid SSL certificate
    • Despite being JSON it should not have a .json extension
    • You can find your Team Prefix here and your app bundle identifier here.
    • Universal Links do not work on the Simulator. Test on a real device.
    • Universal Links do not work when typed directly into Safari - iMessage yourself a valid Universal Link to test.
    • The apple-app-site-association file is cached agressively. If it's not working but you think it should, try re-installing the app.

At this point, tapping a link to your-domain.com should open the app. It won't yet know how to open the specific page we're looking for.

Routing Universal Links

Now that Universal Links are being directed to our app, the app needs to know what to do with them. This is where DeepLink Kit comes in. DeepLink Kit gives you a simple, expressive way to map an incoming URL pattern to either a block or a Class to handle it.

First we need to include DeepLink Kit in our project; if you use CocoaPods simply add the following line to your Podfile.

pod "DeepLinkKit"

Note: If you don't use CocoaPods, you can download the latest version of DeepLink Kit from Github and include it in your project.

The Deep Link Router

At the center of DeepLink Kit is the router - an object that you register routes with and tell it what to do for each. So to begin, we'll create an instance of DPLDeepLinkRouter. Since the URLs are received in your AppDelegate, create a property for your router and initialize it in -application: didFinishLaunchingWithOptions:.

#import <DeepLinkKit/DeepLinkKit.h>

- (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  self.router = [[DPLDeepLinkRouter alloc] init];

  return YES;
}

Our first route

You can add a supported route to the router by directly using the registerBlock:forRouter: method or the literal-access shortcut (router["route"] =). Routes are expressed as patterns with support for named groups and other regex functionality. The route pattern is modeled after Sinatra's and you can find more information about supported routes here.

// This will match http(s)://ANY-DOMAIN.com/product/ANY-IDENTIFIER
self.router[@"/product/:product_id"] = ^(DPLDeepLink *link) {

  // Configure your view controller with the incoming product id.
  ProductDetailViewController *controller = [[ProductDetailViewController alloc] init];
  controller.productId = link.routeParameters[@"product_id"];

  // Present the view controller.
  [self.window.rootViewController presentViewController:controller
                                               animated:NO  
                                             completion:NULL];
};

Note: All of the parameters in the incoming route will be available in the routeParameters property of the DPLDeepLink and all query parameters will be availble in the queryParameters property.

You can add as many routes as you need to the router. e.g.

self.router[@"/settings/:section"] = ^{ };

self.router[@"/product/:product_id/:subsection"] = ^(DPLDeepLink *deepLink) { };

Incoming Links

The application is passed incoming Universal Links to the application: continueUserActivity: restorationHandler: method on the AppDelegate. In this method, we simply pass the incoming NSUserActivity to the router for it to figure out what to do with it.


- (BOOL)application:(UIApplication *)application
        continueUserActivity:(NSUserActivity *)userActivity
        restorationHandler:(void (^)(NSArray *))restorationHandler {

    return [self.router handleUserActivity:userActivity
                            withCompletion:NULL];
}

You're done!

Now your Universal Links should be up and running. If not, check the list of gotchas above in the Configure Your Domain step, this is where it's easiest to miss a requirement.

Can't get it up and running? We're always happy to help - drop us a note at support@usebutton.com or file an Issue on DeepLink Kit.