Deep Linking

Actually, deep linking is not a new word, in the field of web development, from the links to the home page (, deep linking is links to the specific page (… ) . In the field of mobile development, deep linking means that when a mobile app handles a specific URI, it can directly jump to the corresponding content page or trigger specific logic, instead of just starting the app. Such as dianping: / / shopinfo? Id =1859284. If you have Dianping installed on your phone, click this link to go directly to the shop page. The main benefits of doing this are:

  • Preserve context during web and APP switching
  • Inter-app context switch (used to transfer parameters between apps, such as authorization agreement, sharing API, etc.)
  • Web pages can be indexed by search engines, and SEO can increase traffic to increase app downloads and launch rates

Currently, there are two main ways to deal with deep linking:

Custom URL Scheme

For a long time before the emergence of Universal Links, deep linking and communication between apps were mainly realized on iOS through custom URL schemes.

After setting up a custom URL in the Info plist, Handle the URL is the entrance of the app delegate method application: openURL: sourceApplication: 9 begins to be deprecate the annotation: (iOS) or Application: openURL: 9 introduce options: (iOS, but if not implement this method, on the iOS 9 will be compatible with old method call forward, so the general or old method implementation).

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
        sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    BOOL handled = NO;
    // code to handle the URL
    return handled;
Copy the code

Scheme ://user:password@host:port/path? Query# fragments. However, for deep linking, scheme://host/path? The query. Sometimes the path part is omitted and host is used as command. Some apps omit the Query part and use path to pass parameters, which is more RESTful API style. This depends on the complexity of the business logic and how the handler is implemented. A bit is important to note that the specification of the URL is the percentage of encoded, so take the parameters of the need to use stringByReplacingPercentEscapesUsingEncoding: Decode or stringByRemovingPercentEncoding 7 + (iOS) method. On the other hand, spelling a URL stringByAddingPercentEscapesUsingEncoding should be used when: Encode or stringByAddingPercentEncodingWithAllowedCharacters: iOS + 7) method.

The NSURLComponents class can also be used in conjunction with query processing on iOS 7+.

When handling URL, for apps that need to handle less business logic, they can distinguish business logic simply by comparing strings. For complex business logic, especially when URL handlers are maintained across teams, routers need to be introduced to distribute requests. Many articles have been written about the Router, and there are many open source codes available on GitHub for reference or use, such as:

  • DeepLinkKit
  • JLRoutes
  • Routable
  • HHRouter

When choosing a router or implementing it yourself, consider some questions such as: code registration or configuration file; Whether decentralization is needed; How to transfer parameters; Register the handler in view Controller or Block (Closure); Do you need to do web failover like Taobao?…… I’m not going to expand it anymore.

Using URL Schemes to Communicate with Apps

Universal Links

Apple introduced Universal Links in iOS 9. Compared to the Custom URL scheme, Universal Links has the following benefits:

  • The Custom URL Scheme is a Custom protocol, so it cannot be opened directly without app installation. The Universal Links itself is an HTTP/HTTPS link, so it has better compatibility.
  • Different apps can define the same Custom URL scheme, so there will be problems of preemption or conflict, and universal Links is queried from the server by which app, so there is no such problem.
  • Universal Links supports jumping to the target app from MKWebView or UIWebView of another app.
  • Universal Links itself can be indexed by search engines.

The implementation of Universal Links can refer to the official documentation: Support Universal Links. In a nutshell you need to:

  • Add aapple-app-site-associationFile to your website to describe the URL’s association with your app.
  • to specify the domain name from which to query Universal Links support.
  • In the app delegateapplication:continueUserActivity:restorationHandler:Methods handle…userActivity.webpageURL.

The URL itself is handled in a similar way to the custom URL.

Deferred Deep Linking

As the name suggests, deferred deep linking means that a user opens a Web page without installing the corresponding APP and expects the user to deep link to the corresponding content after installing the app. Here are three issues that need to be addressed:

  1. Check whether the APP has been installed. If the app has been installed, direct deep link to the APP; otherwise, jump to the App Store.
  2. User matching, how to match an install to a Web Page view or click.
  3. Deep linking

Question 1

Custom urls are usually handled with a section of javascript like this:

window.location = 'lexie://';  
setTimeout(function() {  
    window.location = 'itms-apps://'
}, 250);
Copy the code

This is because before iOS 9.2, Safari prompts whether to open custom URL with app is blocking JS. Therefore, if users agree to open the link with app, they will not jump to App Store. When the user cancels or does not install the app, it will jump to the App Store. One update Apple made in iOS 9.2 is that this prompt no longer prompts block JS, so it jumps to the App Store anyway. Therefore, it is recommended to use Universal Links to realize such logic. For content that can only be viewed after mandatory app installation, a transfer page can be provided to directly jump to app Store. If an APP is installed, iOS will automatically jump to in-app processing.

The 2016-01-06 update:

After being reminded and tested by @zyg, there are two other cases of logic here on iOS 9.2:……

Code difference: the former is link trigger JS; The latter is triggered directly by onload. Results difference: the former will jump directly to the App Store; The latter does not.

Cause: In Safari, a click event triggers a jump and there is no confirmation whether it is open in the App Store. Jumps triggered by non-user actions have a confirmation prompt. Therefore, when link is clicked in 9.2, the event that jumps to App Store will jump directly because it is not blocked (different from 9.1 and before, the event will not jump because it is blocked). However, the jump triggered directly (such as onload) is blocked by the previous App Store confirmation prompt, so it is not the same as the previous work principle (blocking JS), but at least part of work.

Question 2

This used to be a big problem. It was difficult to track the source of an installation on iOS due to system constraints, but there were many such requirements. The main scenarios were:

  • Tracking AD effectiveness
  • Track user referral/invite links
  • Keep the context of web browsing within the app, such as login information, shopping cart, etc

Before iOS 9, the common approach to this question was to guess, yes, with guessing. Record user characteristics such as IP, system version, phone model, language, etc., when visiting a specific page or clicking on a specific link. Then send these features to the server when opening the app, search for matching links that users have clicked within a period of time (such as 1 hour), and then process this link. The disadvantage of this is obvious, because it is matched by feature blur, so it is easy to miss or match the wrong context. However, most third-party services collect more information from different sources, so the accuracy is much higher than expected, especially if IDFA is turned on.

This problem was solved with the introduction of SFSafariViewController in iOS 9, because SFSafariViewController and Safari cookies are interchangeable! So in theory you can get 100% match. The solution is simple: generate a UUID locally and pass it back to the server via a hidden SFSafariViewController. The server can then map this UUID to the previous session. You can then query for more information about the session using the generic API call. Refer to the Branch SDK implementation for a specific code.

Question 3

As mentioned in the previous section, the entry to the URL is replaced with a callback for an API request.

Branch SDK

There are many third parties offering deep linking and deferred deep linking services, such as AppsFlyer and Branch. Both SDKS are currently available in the Glow app.

The advantage of AppsFlyer is that it has cooperative relations with many companies, such as Facebook, so it performs well in tracking Facebook advertisements. In addition, AppsFlyer supports server callback of many third-party services, which makes it easy to integrate many third-party services. The downside is that AppsFlyer charges for non-organic installs. In addition, the SDK and API doc of AppsFlyer are not very good, and there are many bugs in the follow-up deep link after the installation of Track.

The advantage of Branch is that it is free, the SDK and API doc are written well, and there are special features such as user invitations and rewards that are suitable for operating activities. In addition, Branch can implement a link that automatically jumps to different stores depending on the platform, and can even send traceable links via SMS on the desktop. The downside is that Branch is new, service stability is unproven, and dashboard features are lightweight.

In general, AppsFlyer is more suitable for track advertising effect, and Branch is more suitable for feature realization. It must be mentioned that, because these two services are mainly for the overseas market, so they have encountered the phenomenon of domestic short draught, so the domestic app if you want to use it at your own risk 🙂 if there are similar services in China, you are welcome to leave a message to supplement.

Integration with Branch is relatively simple, see the official documentation. One thing to note is that when you implement a handle URL or a user activity, you can handle the URL directly, but when you use Branch, the first-level URL is the Branch URL. So to the [[Branch getInstance] handleDeepLink: url] and/or [[Branch getInstance] continueUserActivity: userActivity] to a Branch Process, and then process the various arguments in a block (closure) passed in when init Branch:

[branch initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) { if (! error) { // params are the deep linked params associated with the link that the user clicked -> was re-directed to this app // params will be empty if no data found // ... insert custom logic here ... NSLog(@"params: %@", params.description); } }];Copy the code