What Are Universal Links and App Links, and How to Implement Them
In this blog post, we’ll talk about how to implement Universal Links and App Links.
But first, it’s important to understand the fundamental concept of deep linking and to see how Universal Links and App Links came into existence.
What is deep linking?
Deep linking is a technique developers use to enable precise navigation within websites and mobile applications. Think about swiftly accessing ongoing conversations in a messaging app or viewing items added to your shopping cart on an e-commerce platform.
Mobile deep linking
In the context of mobile applications, deep linking is about using a uniform resource identifier (URI) to lead to a specific destination within a mobile app, as opposed to just launching the app. Mobile deep links are often integrated into shortcuts and notifications, letting users access the app's core functionalities with just a single tap. On the web, deep linking works by default, thanks to the underlying technology of HTTP and URLs. Mobile apps, on the other hand, must first be configured to properly handle URIs.
Custom URI schemes for mobile apps
The original method for implementing deep linking in mobile apps was through custom URI schemes. Developers would create a custom URI scheme unique to their applications, which lets them refer to content inside the app and provides a way to launch the app from other apps or processes. For example, an app might register a custom URI scheme like myapp://. The link to specific content would then look like myapp://path/to/content.
Unfortunately, custom URI schemes have several issues. First, there's a noticeable drop in user experience when the app isn't installed. In such cases, the user will simply remain where they were when they clicked the link, without any further guidance. Second, and even more significant, is a possibility of URI collisions, which can lead to potential security issues. This refers to the fact that multiple apps can claim the same myapp:// scheme, so a malicious app can masquerade as the intended app when, say, performing an authorization callback.
Universal Links and App Links are introduced
To avoid these drawbacks, Apple and Google have introduced the next generation of standards for deep linking: Universal Links for iOS and App Links for Android.
Imagine you're managing a travel website that has a companion mobile app. Within your ecosystem, a travel itinerary web link (e.g., https://mytravels.com/itinerary/copenhagen-nordhavn-walk) mirrors an identical journey plan in your app. If the app is installed on the user’s device, clicking the link opens the content within the app. Should the app be missing, the link instead redirects to the mobile browser version of your site. This seamless experience is made possible by Universal Links (iOS) and App Links ( Android).
What are Universal Links?
Universal Links were introduced by Apple in 2015 and are available on iOS version 9 and above. They are standard https:// URLs (e.g., https://mytravels.com), but have the unique ability to connect to the same content deep inside your app and on the corresponding web page.
When a Universal Link is clicked, iOS first checks if the link has been registered for the associated domain. It then checks if the corresponding app is already installed. If the app is present, it gets opened. If not, Safari opens the web version of the content.
This provides developers with a graceful fallback option that was not available with regular deep links. A single link can be used to either open the native app or direct users to a corresponding mobile site. If the app is missing, a Universal Link can also guide users to download it from the App Store. Just keep in mind that you need a mobile website (or at least a functional webserver) to fall back to gracefully if the user does not have the app installed.
What are App Links?
Google introduced App Links as a response to Apple’s Universal Links with the release of Android Marshmallow. App Links are identical to Universal Links in their function: When an https:// link is clicked, the corresponding app will immediately open. For users who don't have the app installed, the requested content will open in a web version.
Unlike standard deep links on Android, App Links won’t present a dialog where a user can choose the browser or a different handler. They will always simply open the app when clicked.
Just like Universal Links, App Links create a bridge between web and app content delivering a better user experience. (Again, you’ll need a functional webserver for graceful fallback.)
How to implement Universal Links
To set up Universal Links and connect specific web pages with in-app destinations, you need to create a two-way association between your app and your website. This involves placing the associated domain file on your website and adding the appropriate entitlement to your app.
A paid Apple Developer account is required to set up Universal Links, as you must associate your fully qualified Apple Developer Team ID.
Here are the general steps to implement Universal Links:
-
Configure your website to host the associated domains file
The apple-app-site-association (AASA) file resides on your website and associates your website domain and your native app. It acts as a proof of domain ownership for iOS. Only you can store this file on your server, which makes Universal Links unique and secure.
When a user installs your app, iOS will attempt to download the AASA file and verify the domains in your entitlement.
- Create your apple-app-site-association file
It contains a JSON object with a list of apps and the URL paths on the domain that should be included or excluded as Universal Links. Here is an example AASA file:
{ "applinks": { "apps": [], "details": [ { "appID": "P56KU6NT8A.com.mytravelapp", "components": [ { "/": "/trip/*", "comment": "Matches any URL with a path that starts with /trip/." } ] } ] } }
appID
is built by combining your Team ID (found under “Membership details” at https://developer.apple.com/account) and the Bundle Identifier (located in the “General” tab of your Xcode project). In the example above, P56KU6NT8A is the Team ID, and com.mytravelapp is the Bundle ID.components
define the rules for handling different types of URLs within the app. This is where you can specify matching URL paths or set specific rules, such as excluding certain links from being treated as Universal Links.
- Place the association file in your site’s .well-known directory
The file’s URL should match the following format: https://<fully qualified domain>/.well-known/apple-app-site-association. It must be hosted using https:// with a valid certificate and no redirects.
- Create your apple-app-site-association file
-
Add the associated domains entitlement to your app
- Register your application with Apple
Your app should be registered at developer.apple.com. - Enable “Associated Domains” on your Xcode project
Open the target’s Signing & Capabilities tab in Xcode, and add the Associated Domains capability. - Add the proper domain entitlement to your app.
Click “Add” (+) at the bottom of the Domains table. Replace the placeholder with the prefix for the service you need (applinks for Universal Links) and your site’s domain. Only include the desired subdomain and the top-level domain, for example: applinks:mytravels.com.
- Register your application with Apple
-
Configure your app delegate to handle Universal Links
When a user taps on a Universal Link, iOS launches your app and you receive aNSUserActivity
object with anactivityType
value ofNSUserActivityTypeBrowsingWeb
. Update your app delegate to respond to the user activity object as described here.If you’re developing with SwiftUI, you can capture Universal Links using the
onOpenURL
instance method. Specifically designed for Universal Links, it lets you register a handler that will be called when your application is opened using a Universal Link, regardless of its state (foreground, background, force-quit).It can be appended to any View, and it takes a URL object as a parameter. In the code snippet below,
onOpenURL
is attached to theNavigationView
, and it prints out the absolute URL string when the app is opened through a Universal Link.struct ContentView: View { var body: some View { NavigationView { Text("Welcome to My Travel App") } .onOpenURL { url in print("Opened URL:", url.absoluteString) } } }
With UIKit, you can use the
UISceneDelegate
object.If your app isn’t running, the system delivers the URL to the
scene(_:willConnectTo:options:)
delegate method after launch.func scene( _ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions ) { // Get URL components from the incoming user activity. guard let userActivity = connectionOptions.userActivities.first, userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingURL = userActivity.webpageURL, let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true) else { return } // Check for specific URL components that you need. // ... }
To handle cases where your app is already running and a URL is being opened, you should implement the scene(_:openURLContexts:) method.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { for context in URLContexts { let url = context.url // handleLink(url) } }
For more information, consult Apple’s official documentation for Universal Links.
How to implement App Links
Implementing App Links is slightly easier. Here are the high-level steps to get App Links working for your app:
-
Create deep links to specific content within your app
- In your app’s manifest, create intent filters for your website URIs.
Intent filters instruct Android to launch your app instead of the website, when a user clicks on a relevant link.
Include the
autoVerify
attribute in your intent filters to prompt the system to automatically verify whether your app is associated with the URL domains specified in your intent filters. It's recommended to addautoVerify
to each<intent-filter>
element for consistency.<activity android:name=".MainActivity"> <!-- ... other activity attributes ... --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="mytravels.com" android:scheme="http" /> <data android:host="mytravels.com" android:scheme="https" /> </intent-filter> </activity>
- Configure your app to read the data from the intents to send users to the right content in your app.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_destination); Intent intent = getIntent(); Uri data = intent.getData(); if (data != null) { // Extract data from the URI and navigate to the corresponding content // Example: Retrieve destination ID and display details } }
- In your app’s manifest, create intent filters for your website URIs.
-
Verify your App Links
App Links rely on the Digital Asset Links API to ensure your app is authorized by the website to open links for that domain. When the system confirms your ownership of the URLs, it automatically directs those URL intents to your app.
- The autoVerify attribute in your intent filters will ensure automatic verification of the app links.
You can also trigger the verification process manually on Android 12 and later versions if you want to test the verification logic. - Declare the association between your website and your intent filters
Create an
assetlinks.json
file and host it on your website at .well-known/assetlinks.json. Here's an exampleassetlinks.json
file that authorizes an app to open links:[{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.mytravels", "sha256_cert_fingerprints": ["1B:9A:6C:2E:33:E5:3E:AE:32:EC:40:97:11:BF:87:76:EE:56:78:EC:2A:3A:62:C9:A4:BC:D0:C2:7A:BC:11:4D"] } }]
-
package_name
is the application ID declared in the app'sbuild.gradle
file.sha256_cert_fingerprints
represents the SHA256 fingerprints associated with your app’s signing certificate. Those can be generated using the Java keytool by running:
keytool -list -v -keystore my-release-key.keystore
For more information, consult the official documentation for App Links on Android
- The autoVerify attribute in your intent filters will ensure automatic verification of the app links.
Summary
Whether you're developing for iOS or Android, Universal Links and App Links are your allies in crafting a smoother, more intuitive user journey.
In terms of security, both rely on HTTP URLs that connect to your website domain, granting exclusive rights to you as a developer. As we saw earlier, confirming domain ownership is an important step of the implementation process.
Both linking strategies are becoming increasingly common. For instance, Universal Links became a requirement when implementing app switching with MitID. The Swedish Bank ID is moving in the same direction.
We hope this guide helped you get an overview of what Universal Links and App Links can do and explained how to incorporate them into your projects.
Happy coding!