Universal Links Made Easy: Web-Mobile Connection for All Developers #1 — iOS World
This article stems from my experience in IT, where I encountered the challenge of migrating a PWA project to native applications, which raised various questions about behaviors, particularly regarding universal links and social login.
Driven by this experience, I decided to share my reflections in this first article. If the feedback is positive and there is engagement, I intend to continue this journey with a second article, addressing the Android world, and including appendices dedicated to Flutter and React Native.
Este post também foi escrito em português, clique aqui para acessar esta versão.
Currently, I am part of and manage a multiplatform mobile architecture team, which allows me to understand the importance of exploring the topic from different angles. I hope this article can be useful and inspiring for other professionals facing similar challenges.
Let’s start with the scenario of a project where you have an email marketing or a landing page and you want to guide the user to click on a certain link, which will then open the installed application on the device.
We have our initial goal set: to click on a specific link and open the installed application.
How do we achieve this? With this in mind, my aim is to bridge the understanding between front-end web professionals and mobile professionals, who will need to work together to achieve this goal.
We’re about to dive into the code part, alright, developer? But before that, I’d like to introduce the topic of Associated Domains.
In terms of Apple’s Associated Domains, we have two distinct types: “webcredentials” and “applinks”. Both serve different purposes and are essential for the integration between apps and websites.
Apple World
Webcredentials: This is a type of Associated Domain that allows an iOS app to declare associations with website credentials. This is useful for single sign-on (SSO) and automatic login credential filling. When a user attempts to log in to a site associated with the app, iOS can automatically suggest the saved app credentials for filling.
Applinks: On the other hand, Applinks are used to link content between your app and your website. They enable you to associate specific URLs on your website with specific content in your app. For example, if you have a link to a specific page on your website and want it to open the corresponding content in your app, you can use Applinks for that. When a user clicks on an associated link on your website, iOS can open the appropriate app, if installed, and navigate directly to the related content.
In an upcoming article, I’ll delve deeper into the Android world, but for Android, there’s no direct equivalent to iOS’s Associated Domains feature. However, there are some related functionalities that can be used for similar purposes:
App Links (Deep Links): Similar to Apple’s Applinks, App Links are links that allow a website to direct users to specific app content if the app is installed on the device. They serve as a way to link content between the app and the website, enabling a smooth transition between the two. When a user clicks on an App Link in a browser, the Android operating system can open the appropriate app and direct the user to relevant content within the app.
Smart Lock for Passwords: This Google feature allows users to save and authenticate automatically in apps and websites without manually typing their credentials. Similar to Apple’s “webcredentials,” Smart Lock for Passwords facilitates single sign-on (SSO) in Android apps and associated websites. When users log in to an app or site that uses Smart Lock for Passwords, they have the option to save their credentials to Google, and Android can then automatically fill in these credentials when needed.
Below is a table summarizing the comparison between iOS and Android resources:
Let’s Dive into the Code
All the code snippets showcased here are available on my GitHub, and the links will be provided at the end of the article. This project serves as the foundation for a series of tests and posts I’m preparing for my mobile development team.
Hence, you might notice that the project structure differs slightly, as I’ve organized it into modules and opted not to use storyboards, among other aspects. However, if you’re just starting out, don’t worry, as I’ll cover the important and relevant points here.
Getting Started with Web Configuration:
Firstly, you need a JSON file named:
apple-app-site-association
ATTENTION! The file must not have the .json extension.
According to the documentation, the file should be placed at the root of your website or inside a folder named .well-known. In this article’s example, this is the format I’ve used.
This will be the basic structure for the content of the file we’ll use in this example:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "35RIDB766W.me.micheltlutz.MobLab",
"paths": [
"/moblab.micheltlutz.me/*"
]
}
]
}
}
The appID attribute is the combination of “TEAMID.BUNDLE ID”. In our case, we’ll use the path attribute only with the subdomain I have configured and any other path that follows after the slash. Do not add any schema (http, https, myapp) to this path.
You can find more details about these settings in the link to the official documentation.
Let’s move to Xcode.
An important point here is that you’ll need a developer account on the developer.apple.com portal. If you’re not going to publish the app, it’s not necessary to pay, just register. You need this because the profiles and certificates linked to your TeamID need to be configured to use Associated Domains. Otherwise, you’ll receive a warning like this:
Where do I find my TeamID?
Once logged in to the Apple developer portal, scroll down the main page until you find the Subscription Information area
First thing we need to do is select the Project in Project Navigator
We go to the Signing & Capabilities tab and add support for Associated Domains, then we need to put our url in an applinks entry:
See the image below:
In the end it should look like the image, remember to use the url of your web project.
Let’s now go to the scheme configuration:
Open the Info.plist File Access the URL types > Item > URL Schemes branch and add the scheme you want to map, in our case moblab
Done, these were the project settings that need to be made, now to finish let’s go to the codes.
Important!
The project is using the most current version of Xcode as of the date of publication (Version 15.3 (15E204a) I configured the project to use UIKit. In this case the project has the AppDelegate.swift file and also the SceneDelegate.swift
Let’s work on SceneDelegate, it will be necessary to create the openURLContexts method where we will carry out the necessary treatments.
The openURLContexts method is a method of the UISceneDelegate protocol, which is called when the scene receives a URL to open. It is used to handle URLs received by your iOS application scene. This method receives a Set of UIOpenURLContext objects, which contains information about the URLs being opened.
Each UIOpenURLContext object contains the URL itself and other relevant information, such as the application opening the URL and the reason the URL is being opened.
By implementing the scene(_:openURLContexts:) method in your SceneDelegate, you can access these UIOpenURLContext objects and process the incoming URLs as needed. This may include manipulating the URL to navigate to a certain screen within your application, extracting information from the URL for further processing, or taking other actions based on the content of the URL.
The scene(_:openURLContexts:) method is critical for handling URLs received by your iOS application and allows you to appropriately respond to those URLs as necessary for your application’s functionality.
Here is a structure of using the method:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else {
return
}
// Checks if the URL has an associated scheme
if let scheme = url.scheme {
// Checks if the schema is as expected
if scheme == "myapp" {
// Do whatever you need to with the URL
// For example, manipulate the URL to navigate to a certain screen
// or extract information from the URL for further processing
}
}
}
In our project we will do the following:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else {
return
}
if let scheme = url.scheme {
if scheme == "moblab" {
appManager?.start(with: url)
}
}
}
In it we will confirm that the scheme is the same as the one we mapped and let’s go, the initial validation is very simple, let’s just check if the scheme is the one we really want to open. If so, you could now load your ViewController.
It’s done, now just run the project on the Emulator or on the Device, access the url of your web project and access the link.
Here for the project the following page was created:
https://moblab.micheltlutz.me/
See the functional demo:
If you are using a previous version of code that does not use SceneDelegate.swift, you will need to do the same procedure in AppDelegate.swift, see the example below:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Checks if the URL has an associated scheme
if let scheme = url.scheme {
// Checks if the schema is as expected
if scheme == "meuapp" {
// Do whatever you need to with the URL
// For example, manipulate the URL to navigate to a certain screen
// or extract information from the URL for further processing
return true
}
}
return false
}
The application(_:open:options:) method is a method of the UIApplicationDelegate protocol, which is called when the application is opened with a URL. It is used to handle URLs received by the iOS application.
This method takes three parameters:
app
: The UIApplication instance representing the application.url
: The URL being opened.options
: A dictionary containing additional information about how the URL is being opened.
The return of this method is a boolean indicating whether the application was able to handle the URL successfully.
Within this method, you can check the received URL and take appropriate actions based on the content of the URL, in the same way as done in openURLContexts.
Until next time, if you’ve read this far please leave at least 1 clap.
Repositories
Site: https://github.com/micheltlutz/moblab-site
App: https://github.com/micheltlutz/moblab-ios
Winged-Python: https://github.com/micheltlutz/Winged-Python
References:
Mys Dev.to post https://dev.to/micheltlutz/universal-links-made-easy-web-mobile-connection-for-all-developers-1-ios-world-5bia