0

Here is the code I currently have however, it does not seem to be working. This example says I want to open the calc app. My goal is to open an app once a widget is clicked.

@main App Code:

var body: some Scene {
    WindowGroup {
        ContentView()
            .onOpenURL { url in
                print("Received deep link: \(url)")
            }
    }
}

Widget Code:

Gauge(value: 50), in: 0.0...100.0) {
            } currentValueLabel: {
                Text(Open App)
            }
            .gaugeStyle(.accessoryCircularCapacity)
            .widgetURL(URL(string: "calc://")!)

1 Answers1

1

Then you need to do this in a 2 step process. First, you need to set up your app to receive custom URLs from your widget. This is shockingly well explained by Apple here. Once you have your app's custom url scheme set up, it is time to set up your widget. Essentially what you are going to do is send a URL with a query that is the URL you want to open. Back in your app, you receive that URL, parse it out, and then call openUrl() with the URL you want to open, and that app will open.

Your code above is close. Following Apple's example above, try this:

In your widget create a deep link URL:

func createDeeplinkForCalc() -> URL {
    var components = URLComponents()
    components.scheme = "myphotoapp"
    components.host = "com.example.myphotoapp"
    components.path = "/calc"
    components.queryItems = [
        URLQueryItem(name: "open", value: "calc://")
    ]
    
    return components.url!
}

Then, in .widgetURL, pass this: .widgetURL(createDeeplinkForCalc())

In your main app:

var body: some Scene {
    WindowGroup {
        ContentView()
            .onOpenURL { url in
                handleURL(url: URL)
            }
    }
}

func handleURL(_ url:URL) {
    // This makes sure you got the correct URL
     guard url.scheme == "myphotoapp",
         url.host == "com.example.myphotoapp"
     else { return }
        
     let query = parseQuery(url: url)

     guard let urlString = query["open"],
           !urlString.isEmpty else { return } // make sure something exists in the value

     if let calcURL = URL(string: urlString) {
         openURL(calcURL) // this calls "calc://" and opens the calculator
    }

    private func parseQuery(url: URL) -> Query {
         guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
               let queryItems = components.queryItems
         else { return ["":""] }
        
          return queryItems.reduce(into: Query()) { (result, item) in
            result[item.name] = item.value
        }
    }
}

The above has not been tested, but should work.

Yrb
  • 8,103
  • 2
  • 14
  • 44