Skip to content
advanced Phase 4 · Navigation & Data Flow

Deep Linking

Handle URL schemes, universal links, and push notification routing in SwiftUI.

55m
3 problems
Topic Progress 0%

URL Schemes

What Are URL Schemes?

URL schemes let your app handle custom URLs like myapp://profile/42. When a user taps such a link (from Safari, another app, or a universal link), iOS opens your app and passes the URL to it.

Registering a URL Scheme

In your Xcode project, go to your target's Info tab and add a URL Type:

  1. Click + under URL Types
  2. Set Identifier to your bundle ID
  3. Set URL Schemes to your scheme name (e.g., myapp)
  4. Set Role to Editor

Or add it to Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>myapp</string>
        </array>
        <key>CFBundleURLName</key>
        <string>com.yourcompany.yourapp</string>
    </dict>
</array>

Handling Incoming URLs

In SwiftUI, use .onOpenURL:

struct ContentView: View {
    var body: some View {
        TabView {
            HomeView()
                .tabItem { Label("Home", systemImage: "house") }
        }
        .onOpenURL { url in
            handleDeepLink(url)
        }
    }

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

        if components.host == "profile" {
            let userId = components.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
            // Navigate to profile
        }
    }
}

URL Parsing

Parse deep link URLs to extract routing information:

enum DeepLink {
    case profile(userId: String)
    case post(postId: String)
    case settings

    init?(url: URL) {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return nil }

        switch components.host {
        case "profile":
            let userId = components.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
            self = .profile(userId: userId)
        case "post":
            let postId = components.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
            self = .post(postId: postId)
        case "settings":
            self = .settings
        default:
            return nil
        }
    }
}

Universal URL Schemes

Common schemes include http, https, mailto, tel. Custom schemes like myapp:// are app-specific and don't transfer if the app isn't installed.

For production apps, prefer Universal Links (HTTPS-based) over custom URL schemes for better security and reliability.

Push Notification Routing

Deep Linking via Push Notifications

Push notifications can carry data payloads that route users to specific content. When a user taps a notification, your app opens and you handle the payload.

Notification Payload Structure

{
    "aps": {
        "alert": {
            "title": "New Message",
            "body": "You have a new message from Alice"
        },
        "badge": 1
    },
    "deepLink": {
        "type": "message",
        "id": "12345"
    }
}

Handling Notification Launch

When the app is launched from a notification, the payload is available in AppDelegate:

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    if let notification = launchOptions?[.remoteNotification] as? [AnyHashable: Any] {
        handleNotificationPayload(notification)
    }
    return true
}

In SwiftUI with the new lifecycle:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onReceive(NotificationCenter.default.publisher(for: .didReceiveNotification)) { notification in
                    if let payload = notification.userInfo {
                        handleNotificationPayload(payload)
                    }
                }
        }
    }
}

Routing Notification Data

Create a notification router that translates payloads to navigation actions:

struct NotificationRouter {
    static func handle(payload: [AnyHashable: Any]) {
        guard let deepLink = payload["deepLink"] as? [String: Any],
              let type = deepLink["type"] as? String,
              let id = deepLink["id"] as? String else { return }
        switch type {
        case "message":
            NavigationManager.shared.navigateTo(.conversation(id: id))
        case "post":
            NavigationManager.shared.navigateTo(.post(id: id))
        default:
            break
        }
    }
}

Background Notification Handling

For notifications received while the app is in the background, use a Notification Service Extension to modify or decrypt the payload before display.

Combining Deep Link Sources

A robust deep link handler unifies URL schemes, universal links, and push notifications into one routing system. The key is that all three ultimately produce a route enum that your NavigationStack processes.

Quiz

1. What is the main advantage of Universal Links over custom URL schemes?

Question 1 options

2. Where is the apple-app-site-association file hosted?

Question 2 options

3. Which SwiftUI modifier handles incoming deep link URLs?

Question 3 options

4. What is the Associated Domains entitlement format for Universal Links?

Question 4 options

Flashcards

Question

What are Universal Links?

Answer

HTTPS URLs that open your app when installed, or your website in Safari when not installed. Verified by Apple via apple-app-site-association file.

Question

How do you register a custom URL scheme?

Answer

Add CFBundleURLTypes to Info.plist with CFBundleURLSchemes array containing your scheme name.

Question

What SwiftUI modifier handles incoming URLs?

Answer

.onOpenURL { url in } handles both custom URL schemes and universal links.

Question

How do push notifications enable deep linking?

Answer

Notification payloads contain a deepLink dictionary with type and id, which the app routes to the appropriate screen.

Revision Notes

Key Takeaways

  • 1. URL schemes use custom protocols (myapp://) registered in Info.plist
  • 2. Universal Links are HTTPS URLs verified by Apple via AASA file
  • 3. Push notifications can carry deep link payloads for routing
  • 4. .onOpenURL is the SwiftUI entry point for handling deep links
  • 5. A unified DeepLinkHandler routes all deep link sources through one system

Interview Tips

  • Explain the difference between URL schemes and Universal Links
  • Know how to structure and host an apple-app-site-association file
  • Describe how push notification payloads can trigger navigation
  • Discuss deep link security considerations (verification, spoofing prevention)

Cheat Sheet

URL Schemes: Custom scheme (myapp://) registered in Info.plist under CFBundleURLTypes.

Universal Links: HTTPS links verified by apple-app-site-association file. Associated Domains: applinks:domain.com.

Push Notification Routing: Payload contains deepLink dict with type/id. App routes on launch.

.onOpenURL handles all incoming URLs in SwiftUI.

For production: prefer Universal Links over custom schemes for security.