How to Handle Deep Links in UIKit

Learn how to implement and handle both custom URL schemes and Universal Links │ in your UIKit application to navigate users to specific content.

Intermediate

Handling deep links in UIKit involves two primary mechanisms: Custom URL Schemes and Universal Links. While both allow users to navigate directly to specific content within your app, Universal Links are generally preferred for their seamless user experience and better fallback behavior.

1. Custom URL Schemes

Custom URL schemes allow you to define a unique prefix for your app's URLs (e.g., myapp://product/123). When a user taps a link with this scheme, iOS launches your app.

Setup:

  1. Register the URL Scheme in Xcode:

    • Open your project in Xcode.
    • Select your project in the Project Navigator, then select your target.
    • Go to the "Info" tab.
    • Under the "URL Types" section, click the "+" button to add a new URL type.
    • For "Identifier," you can use your app's bundle ID (e.g., com.yourcompany.yourapp).
    • For "URL Schemes," enter your desired custom scheme (e.g., myapp).
  2. Handle the Incoming URL in AppDelegate or SceneDelegate:

    • For apps using AppDelegate (older apps or those not using Scene Delegates): Implement the application(_:open:options:) method.

      swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { // Parse the URL and navigate to the appropriate content print("Received URL: \(url)") handleDeepLink(url) return true }

    • For apps using SceneDelegate (iOS 13 and later): Implement scene(_:openURLContexts:) or scene(_:continue:).

      ```swift func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let url = URLContexts.first?.url else { return } print("Received URL: (url)") handleDeepLink(url) }

      // For Universal Links, you'll also use this method func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return } print("Received Universal Link: (url)") handleDeepLink(url) } ```

2. Universal Links

Universal Links are standard HTTPS links that work for both your website and your app. If your app is installed, the link opens directly in your app; otherwise, it opens in Safari. This provides a much smoother user experience.

Setup:

  1. Create an apple-app-site-association file:

    • This JSON file tells iOS which URLs your app can handle.
    • Host this file at the root of your web server or in the .well-known subdirectory (e.g., https://yourdomain.com/apple-app-site-association).
    • Example content: json { "applinks": { "apps": [], "details": [ { "appID": "TEAM_ID.com.yourcompany.yourapp", "paths": [ "/product/*", "/settings/*" ] } ] } } Replace TEAM_ID and com.yourcompany.yourapp with your actual values.
  2. Enable Associated Domains Capability in Xcode:

    • In Xcode, select your project and target.
    • Go to the "Signing & Capabilities" tab.
    • Click "+ Capability" and select "Associated Domains."
    • Add an entry for each domain your app should handle, prefixed with applinks: (e.g., applinks:yourdomain.com).
  3. Handle the Incoming URL in AppDelegate or SceneDelegate:

    • Universal Links are handled using the NSUserActivity object.
    • For AppDelegate: Implement application(_:continue:restorationHandler:).

      swift func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return false } print("Received Universal Link: \(url)") handleDeepLink(url) return true }

    • For SceneDelegate: Use the scene(_:continue:) method as shown in the Custom URL Schemes section above.

3. General Deep Link Handling Logic (handleDeepLink function)

Regardless of whether you use custom URL schemes or Universal Links, the core logic for parsing the URL and navigating within your app remains similar.

func handleDeepLink(_ url: URL) {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
        return
    }

    // Example: myapp://product/123?color=red
    // Example: https://yourdomain.com/product/123?color=red

    if components.host == "product" {
        // Extract product ID from path components or query parameters
        let productID = components.path.replacingOccurrences(of: "/", with: "")
        let color = components.queryItems?.first(where: { $0.name == "color" })?.value

        // Navigate to product detail screen
        // (e.g., using a UINavigationController or presenting a new view controller)
        if let rootViewController = UIApplication.shared.windows.first?.rootViewController as? UINavigationController {
            let productViewController = ProductDetailViewController() // Your custom VC
            productViewController.productID = productID
            productViewController.selectedColor = color
            rootViewController.pushViewController(productViewController, animated: true)
        }
    } else if components.host == "settings" {
        // Navigate to settings screen
        if let rootViewController = UIApplication.shared.windows.first?.rootViewController as? UINavigationController {
            let settingsViewController = SettingsViewController() // Your custom VC
            rootViewController.pushViewController(settingsViewController, animated: true)
        }
    }
    // Add more conditions for different paths/hosts
}

4. Security Considerations

Deep links can be a potential attack vector. Always validate all URL parameters and discard any malformed URLs. Limit actions available through deep links to those that don't risk user data, and never allow them to directly delete content or access sensitive information.

5. Testing Deep Links

You can test deep links by: * Entering the custom URL scheme in Safari (e.g., myapp://product/123). * Using the xcrun simctl openurl booted <URL> command in your terminal to open URLs in the iOS Simulator. * Tapping on Universal Links from a webpage in Safari.