Menu

Deep Links

Deep links allow you to bring a user to a particular part of your app. Skip supports custom URL schemes and SwiftUI deep link handling.

Darwin Setup

To support deep links in your iOS build, first follow Apple’s instructions to register your custom URL scheme in Xcode.

Xcode screenshot of adding a custom URL scheme

Only pay attention to the instructions for registering your custom URL scheme. Ignore the remaining instructions about handling deep links in your code, because you’ll be using SwiftUI’s deep link processing instead.

Android Setup

Edit your Android build’s AndroidManifest.xml to add an intent-filter for your custom URL scheme. For example to support myurlscheme, add the following to your AndroidManifest.xml:

<manifest ...>
    ...
    <application ...>
        ...
        <activity ...>
            ...
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="myurlscheme" />
            </intent-filter>
        </activity>
    </application>
</manifest>

While iOS is flexible, Android will expect deep link URLs with the general form scheme://host or scheme://host/path.

SwiftUI

SwiftUI uses the onOpenURL view modifier to intercept and process deep links. Place the modifier on a view that will be rendered when the app opens, and use its action to process the given URL. This will typically involve updating your navigation bindings to take the user to a specified location in the app, as in the following sample:

enum Tab : String {
    case cities, favorites, settings
}

public struct ContentView: View {
    @AppStorage("tab") var tab = Tab.cities
    @State var cityListPath = NavigationPath()

    public var body: some View {
        TabView(selection: $tab) {
            NavigationStack(path: $cityListPath) {
                CityListView()
            }
            ...
            .tag(Tab.cities)

            NavigationStack {
                FavoriteCityListView()
            }
            ...
            .tag(Tab.favorites)

            SettingsView()
                ...
                .tag(Tab.settings)
        }
        // travel://<tab>[/<city>], e.g. travel://cities/London or travel://favorites
        .onOpenURL { url in
            if let tabName = url.host(), let tab = Tab(rawValue: tabName) {
                self.tab = tab // Select the encoded tab
                if tab == .cities, let city = city(forName: url.lastPathComponent)) {
                    // iOS needs an async dispatch after switching tabs to read navigationDestinations
                    DispatchQueue.main.async {
                        // Set nav stack to root + specified city
                        cityListPath.removeLast(cityListPath.count)
                        cityListPath.append(city.id)
                    }
                }
            }
        }
    }
}

Testing

On iOS, the easiest way to test your deep link handling is by entering a URL with your custom scheme into Safari. You can also write a URL into a Calendar event or a Note. iOS will linkify the text so that tapping it will open your app.

Android includes an adb command for sending intents to the running emulator or device, including deep links. Building on our SwiftUI example above, enter a command like the following in Terminal:

% adb shell am start -W -a android.intent.action.VIEW -d "travel://cities/London"