Deep linking in iOS is the practice of leveraging contextual links to drive a user to specific in-app content. For example, if you tap a link to a song on a website, it can open your music app and play that song directly, instead of opening the website in a browser.
Deep linking can improve user experience, engagement, retention and conversion rates for your app. However, it can also be challenging to implement correctly and consistently across different platforms and devices.
Remember to handle the deep link appropriately within your app once it’s opened. You can use custom URL schemes or Universal Links for deep linking, depending on your requirements and the iOS versions you are targeting.
Apple supports common schemes associated with system apps, such as mailto
, tel
, sms
, and facetime
.
mailto:frank@wwdcdemo.example.com
tel:1-408-555-5555
facetime://user@example.com
sms:1-408-555-1212
In the context of iOS deep linking, both URL schemes and URI schemes are technically the same. The term “URI scheme” is a broader term encompassing various naming conventions used to identify resources on a network, while “URL scheme” specifically refers to the part of a Uniform Resource Locator (URL) that specifies the protocol used to access the resource.
However, in the context of iOS development, “URL scheme” is the commonly used term when referring to deep linking. It defines a custom protocol used to launch your app and potentially navigate to specific content within the app.
myphotoapp:albumname?name="albumname"
myphotoapp:albumname?index=1
Then you register your scheme so that the system directs appropriate URLs to your app. Register your scheme in Xcode from the Info
tab of your project settings. Update the URL Types
section to declare all of the URL schemes your app supports.
And finally you handle the URLs that your app receives in AppDelegate.
func application(
_ application: UIApplication,
open url: URL,
options: [UIApplicationOpenURLOptionsKey: Any] = [:]
) -> Bool {
// Determine who sent the URL.
let sendingAppID = options[.sourceApplication]
print("source application = \(sendingAppID ?? "Unknown")")
// Process the URL.
guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
let albumPath = components.path,
let params = components.queryItems
else {
print("Invalid URL or album path missing")
return false
}
// ...
}
Universal Links are supported on iOS 9 and later versions. They allow apps to claim ownership of specific web domains and open specific content within the app when a user taps on a link to that domain.
These are standard HTTP or HTTPS links that can open your app if it is installed, or fall back to your website if it is not. Universal links are more secure and user-friendly than custom URL schemes, and they also support link attribution and measurement.
https://myphotoapp.example.com/albums?albumname=vacation&index=1
https://myphotoapp.example.com/albums?albumname=wedding&index=17
To support universal links in your app:
Add a JSON file named apple-app-site-association
(without an extension) to your website in .well-known
directory and must be served over HTTPS. The file’s URL should match the following format: https://your-domain/.well-known/apple-app-site-association
.
{
"applinks": {
"details": [
{
"appIDs": ["TeamID.BundleID"],
"components": ["/path1/*", "/path2/deep-link"]
}
]
}
}
Remember to update the example file with the appropriate App IDs, paths, and your own domain. Only you can store this file on your server, securing the association of your website and your app.
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
// Get URL components from the incoming user activity.
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingURL = userActivity.webpageURL,
let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true)
else {
return false
}
// Check for specific URL components that you need.
// ...
}
Some of the benefits of using universal links are:
While custom URL schemes are an acceptable form of deep linking, universal links are strongly recommended.
Communicating between apps using deep links means that one app can launch another app and pass data to it using specially formatted URLs.
open(_:options:completionHandler:)
in UIKitif let appURL = URL(string: "https://myphotoapp.example.com/albums?albumname=vacation&index=1") {
UIApplication.shared.open(appURL) { success in
if success {
print("The URL was delivered successfully.")
} else {
print("The URL failed to open.")
}
}
} else {
print("Invalid URL specified.")
}
openURL
action in SwiftUIstruct OpenURLExample: View {
@Environment(\.openURL) private var openURL
var body: some View {
Button {
if let url = URL(string: "https://www.example.com") {
openURL(url)
}
} label: {
Label("Get Help", systemImage: "person.fill.questionmark")
}
}
}
onOpenURL
modifier. This modifier allows you to specify a closure that will be executed when your app is launched or resumed with a deep link URL.@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
// Handle the deep link URL
handleDeepLink(url)
}
}
}
func handleDeepLink(_ url: URL) {
// Handle the deep link URL
// You can extract any necessary information from the URL
// and perform the appropriate actions in your app
print("Deep link URL: \(url)")
// Example: Handle a specific deep link scheme and path
if url.scheme == "your-deep-link-url-scheme" && url.path == "/your-path" {
// Perform actions specific to this deep link
// ...
}
}
}
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.
// ...
}
Implement the scene(_:openURLContexts:)
method, which is called when your app is already running and a deep link URL is being opened.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for context in URLContexts {
let url = context.url
// handleDeepLink(url)
}
}