iosswiftswiftui

SwiftUI: openURL vs. Link


What's the difference between the two possibilities? They both seem to work the same way.

struct ContentView: View {
  @Environment(\.openURL) private
  var openURL

  let url = "https://google.com"

  var body: some View {
    VStack(spacing: 25) {
      Button("Go to Google via openURL") {
        openURL(URL(string: url) !)
      }
      Link(destination: URL(string: url) !, label: {
        Text("Go to Google-Search via Link")
      })
    }
  }
}

Solution

  • The openURL environment value is something you can call from anywhere, whereas Link is a View that can only be triggered by a user. They are very different.


    I will assume that you are asking about the difference between a Button that calls openURL and a Link.

    You can try dumping the body of a Link.

    let link = Link(destination: URL(string: "https://google.com")!, label: {
      Text("Go to Google-Search via Link")
    })
    let _ = dump(link.body)
    

    On iOS 18.1, it shows that the body is of this type:

    SwiftUI._ConditionalContent<
        SwiftUI.ModifiedContent<
            SwiftUI.ModifiedContent<
                SwiftUI.Button<SwiftUI.Text>,
                SwiftUI.(unknown context at $1d30f33c8).IgnoreViewRespondersModifier
            >,
            SwiftUI.AccessibilityAttachmentModifier
        >,
        SwiftUI.ModifiedContent<
            SwiftUI.Button<SwiftUI.Text>,
            SwiftUI.AccessibilityAttachmentModifier
        >
    >
    

    As you can see from the output, it's just a Button modified with some accessibility modifier. It can be shown that the button's action calls openURL at some point, by setting openURL to something else using .environment.

    From the dump, it seems like the accessibility modifier likely is

    .accessibilityAddTraits(.isLink)
    

    in addition to an accessibility property containing the destination URL.

    There is also the IgnoreViewRespondersModifier which gets added conditionally in the true branch, but I have been unable to find a case where the true branch is executed.


    As with everything that is undocumented, this may very well change in future versions.