swiftuiurl-schemestring-interpolation

Use string interpolation and custom URL scheme


I'm trying to display a Text with different URLs in swiftUI but face an issue with string interpolation.

I used the instruction here to add a custom URL scheme to my test app and when I use a basic test URL it works:

Text("[\(text)](urlschemetest://action)")
.onOpenURL { link in
   print("LINK: \(link)")
}

When I create the the same with a string interpolation within the URL part though the link doesn't work anymore.

Text("[\(text)](urlschemetest://\(actionVariable))")
.onOpenURL { link in
   print("LINK: \(link)")
}

Is there a way to have string interpolation to work or to populate the URL dynamically from a variable?

I assume I'm missing something simple but could not find anything related to this issue with my searches.

The goal is to use an array of words and connect each to its own URL. I currently use reduce on the array to build the string:

arrayObj.reduce(Text(""), {
    $0 + Text("[\($1.word)](baps://action/\($1.urlAction!)) ") + Text(" ")
} )

Solution

  • Use this example code (using AttributedString or Link) to ...have string interpolation to work or to populate the URL dynamically from a variable..

    struct ContentView: View {
        @Environment(\.openURL) var openURL
        
        let query = "?q=swiftui&atb=v201-4__&hps=1&ia=web"
        let prompt = "Search for SwiftUI"
        
        var body: some View {
            VStack (spacing: 55) {
                // using AttributedString
                if let txt = try? AttributedString(markdown: "[\(prompt)](https://duckduckgo.com/\(query))") {
                    Text(txt)
                        .environment(\.openURL, OpenURLAction { url in
                            print("\n---> Text: \(url)")
                            return .systemAction
                        })
                }
                // alternative, using Link
                if let linkUrl = URL(string: "https://duckduckgo.com/\(query)") {
                    Link(prompt, destination: linkUrl)
                        .environment(\.openURL, OpenURLAction { url in
                            print("\n---> Link: \(url)")
                            return .systemAction
                        })
                        .foregroundColor(.red)
                }
            }
        }
    }
    

    EDIT-1:

    Your question was: Is there a way to have string interpolation to work or to populate the URL dynamically from a variable?, now you are saying Is there a way to have that without a variable?.

    What variable are you referring to?

    With your .reduce, I suggest you use String, and then after getting the results use the AttributedString, such as:

         let results = arrayObj.reduce("", {
              $0 + "[\($1.word)](baps://action/\($1.urlAction)) " + " "
          } )
                
         if let txt = try? AttributedString(markdown: results) {
             Text(txt)
         }
    

    Note, do not use forced unwrapping ! in your code, it is a recipe for a crash.