Overview

With WWDC20, Apple introduced SwiftUI 2.0 and a lot of the new features coming with iOS 14. Following last year’s keynote, these new features will only be supported by SwiftUI.

To make it even more attractive, Apple released the new SwiftUI app life cycle: apps written 100% in SwiftUI. Just by using @main and conforming to the new protocol, App we can tell Xcode where the starting point of our application is. But what happens with UIKit’s AppDelegate? This file was handy to:

  • Configure third-party libraries on start
  • Handle notifications
  • Handle deep and universal links

In this tutorial, we’ll focus on deep links and learn how to use SwiftUI’s new modifiers to listen to these events as well as present a neat and clean approach to handle them. Notice that whatever we say about deep links applies to universal links as well. The only addition is you need to support associated domains.


Introduction: Trips Calendar

In this article, we’ll be using this sample app called Trips Calendar. This app displays a list of your trips and lets you navigate to a detail view. You can also add or remove a trip.

Image for post

Home screen

How can we implement deep linking so a user can navigate to the detail view just by using SwiftUI code? We’ll see how to deal with deep linking in the next few sections.You can find the whole implementation of this tutorial in my repository here:

Setting App Deep Links

If you’re familiar with setting up URL types in your app, you can skip this section. Otherwise, keep reading.

Deep links are just URLs with a scheme that points unequivocally to your app. For example, for Trips Calendar, we could come up with a scheme like tcal_. _This way, any URL with this scheme would start our App.

To do so, go to your project file in Xcode. Select your target, go to “Info,” and scroll down until you find “URL Types.” Hit the + button, and add your scheme under “URL schemes.”

Image for post


Handling Deep Links

SwiftUI 2.0 comes with a new modifier, onOpenURL. This modifier is available in any View. Whereas you could simply implement onOpenURL on any View that might need it, it’s not a good idea — you’ll most likely be repeating code to handle the deep link, that is, to determine the action to be performed for a particular link.

My proposed solution is to use App to do this handling and use the environment to propagate the link and react to that change accordingly.

@main
struct TripsCalendarApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL {
                    // code here
                }
        }
    }
}

Resolving deep links

DeepLinker’s only purpose is to handle deep links. Now, there are two kinds of deep links that Trips Calendar is interested in:

  • home: to just open the app on its home screen
  • details: to navigate to the detail view
class Deeplinker {
    enum Deeplink: Equatable {
        case home
        case details(reference: String)
    }
    ...
}

Now, why would we want to handle URLs to the home screen? Well, this is the screen that’s usually first presented to any user when the app starts, but what happens if the user is in any screen in your app, goes to the background, and hits a deep link? In this case, there’s no navigation forward — only backward. This is something we want to be able to handle too:

func manage(url: URL) -> Deeplink? {
    guard url.scheme == URL.appScheme else { return nil }
    guard url.pathComponents.contains(URL.appDetailsPath) else { return .home }
    guard let query = url.query else { return nil }
    let components = query.split(separator: ",").flatMap { $0.split(separator: "=") }
    guard let idIndex = components.firstIndex(of: Substring(URL.appReferenceQueryName)) else { return nil }
    guard idIndex + 1 < components.count else { return nil }

    return .details(reference: String(components[idIndex.advanced(by: 1)]))
}

So basically, Trips Calendar Deep Linker checks the URL scheme to make sure it matches the app scheme. If no URL path is found, it defaults to the home screen. Otherwise, it looks for a parameter in the URL query to create the details deep link.

So now from the App file, we can handle deep links and perform actions when the URL is recognized:

.onOpenURL { url in
    let deeplinker = Deeplinker()
    guard let deeplink = deeplinker.manage(url: url) else { return }

    // do something
}

#ios #mobile #programming #swiftui #swift

Deep Links, Universal Links, and the SwiftUI App Life Cycle
18.05 GEEK