Deep-linking on iOS
This is an extended version of the talk I gave at the CocoaHeads 115 meetup, which was organized in the Shpock HQ in Vienna.
You can read other Shpock Tech posts on Medium.
What is deep-linking?
Deep-linking is a way to link users directly to your app, actually to a specific screen or state within your app. They can appear as links shared directly between people, as search engine results, behind posts on social media platforms, in e-mails...
One way of doing deep-linking also enables communication between two apps on the same device. I'll explain this later in the Custom Schemes section.
Deep-linking is supported on both iOS and Android, with only some differences.
Why would you use it?
The main reason behind using deep-linking is to improve the user experience when transitioning from one app or website to your app. By supporting deep-linking, your users will be able to seamlessly continue their intent, and not lose the context.
For example, let's say you have an app like Shpock that contains many product listings. When a user shares a link to a product with another person, the receiver should be able to open that link and afterwards land directly on the shared item, even when having to install the app in between. The same applies for links to products that Google has indexed.
Improving the transition between the origin (shared link, search engine result..) and the destination (correct app screen) inevitably increases the conversion rate for those users. If your users don't have to jump through hoops or manually search for the content within your app again, they are more likely to interact with or consume that content.
What can you do with deep-linking?
Here are some of the examples possible with deep-linking:
- Take your users exactly to the shared content
- Apply referral or coupon codes by embedding the referral / coupon code in the deep-link
- Customize your app behavior based on what you already know about the user, for example: on an outdoor billboard promote a shortened app download URL containing location information.
- Use custom scheme to handover information to other apps (for example, sharing on instagram stories)
- Use it from within the app (marketing content, in-app HTML, native buttons with dynamic destinations, to take the user to a specific location in the app or perform an action)
How to support deep-linking?
There are 2 main ways of supporting deep-links, and in order to have the best user experience and flexibility I recommend you to support both:
- Universal Links (iOS) / Android App Links
- Custom schemes
Apple says they are:
- Unique - because no other app can claim to handle your URLs.
- Secure - since your app configuration is pointing towards your web domain, and your web domain is pointing to only your app, which gets verified by iOS on app installation.
- Flexible - universal links work whether your app is installed or not. If it's not installed, the user will land on your website.
- Simple - they work for both web and native apps.
- Private - for other apps to communicate to yours, they don't need to know your custom scheme or whether the app is installed or not. They can just trigger the standard web URL.
Implementing Universal Links is done in a few steps:
- Configure your app in Xcode to know about your website.
- Configure your website to know about your app.
- Implement App Delegate changes in your app to handle incoming URLs.
Below you can see how Universal Link handling flow looks like for a sample Shpock item URL:
Custom Schemes work by every app defining its own "protocol" (e.g. "shpock://") for whose handling it registers itself responsible. The three main downsides of custom schemes are that they are not unique, i.e. they are taken on a first-come-first-served principle, and that they cause a privacy issue. You can use custom schemes to check if an app is installed if you know its custom scheme (canOpenURL:). That is why Apple started limiting the number of different allowed canOpenURL: calls for each app.
A sample custom scheme URL for Shpock looks like this:
- shpock://shpock.com/item/5da46dc3babfce01a2183278/ - try it out with Shpock installed vs not installed
Did you think I forgot about the third main downside? Nope. The 3rd main downside is that custom scheme URLs don't work if your app is not already installed on a user's device. If they try to open such a link and don't already have the app, they will get an error. That's why Universal Links are better - the user will at least land on your website, where you can give them an App Store download link.
One way to overcome this last issue is to use a separate service which will try to check if your app is installed, and if it's not - take the user to the App Store. I tried two such services and both work fine:
They work similarly, and the flow for what we at Shpock use with AppsFlyer's OneLink looks like this:
If you look at the flow graph above, you will see that there is a way to pass the user's intent (deep-link) to the app even after them having to install it first. This is called deferred deep-linking, and can be done using any of the above linked 3rd party services.
Web <meta /> Tags
In order to inform services like Google or Facebook that your website content is also available in your app, you can use appropriate HTML meta tags. Here as well, there are multiple standards, and I recommend to support both because it is easy.
Basically you add HTML tags that tell which app your website is related to (separate tag for each platform like iOS or Android), and which Custom Scheme URL can be used to load that content in your app.
Handoff is an Apple technology related to deep-linking and it's worth mentioning here. It is useful when the user wants to continue doing something while switching between multiple devices. For example, they could be using your app on their mobile device, and if they switch to a computer they can easily open the exact same content in their desktop native app (if you have it) or their web browser.
Supporting Handoff is also easy:
- Create a user activity object (NSUserActivity) for every content / action your user is viewing / doing in your app and keep updating it as user keeps moving throughout your app.
- Continue the user activity on a different device when the user requests it, by supporting appropriate App Delegate callbacks.