`scene(_ scene: UIScene, continue userActivity: NSUserActivity)` doesn't get called when the app is launched after the user clicks on a universal link
Asked Answered
V

5

19

Method scene(_ scene: UIScene, continue userActivity: NSUserActivity) doesn't get called when the app is launched after the user clicks on a universal link.

It works fine when already launched app opens again after the user clicks on the universal link. The sample code:

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
        let incomingURL = userActivity.webpageURL,
        let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true),
        let path = components.path else {
            return
    }
    let params = components.queryItems ?? [URLQueryItem]()

    print("path = \(path)")
    print("params = \(params)")
}

I tried to use application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration, but it never gets called when the user clicks on the link:

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    if let scene = connectingSceneSession.scene, let userActivity = scene.userActivity {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
            if let incomingURL = userActivity.webpageURL,
                let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true),
                let path = components.path {
                let params = components.queryItems ?? [URLQueryItem]()

                print("path = \(path)")
                print("params = \(params)")
            }
        }
    }
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

I tried to use scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions):

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let userActivity = scene.userActivity {
        self.scene(scene, continue: userActivity)
    }
}

I also tried the following methods:

func sceneDidBecomeActive(_ scene: UIScene) {
    if let userActivity = scene.userActivity {
        self.scene(scene, continue: userActivity)
    }
}

func sceneWillEnterForeground(_ scene: UIScene) {
    if let userActivity = scene.userActivity {
        self.scene(scene, continue: userActivity)
    }
}

But scene.userActivity is always nil there and I can't get userActivity.webpageURL.

How can we recognize that the link was clicked and the app was launched (not just opened)?

Voiceful answered 4/10, 2019 at 22:43 Comment(1)
Related (possibly the same underlying issue): #58135206Cd
V
16

You almost had it:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let userActivity = scene.userActivity { // <-- not quite
        self.scene(scene, continue: userActivity)
    }
}

It's not in the scene; it's in the connectionOptions . Look in the connectionOptions.userActivities. (Though if what has happened is that the user clicked a link to launch us, I would expect to find the URL in the connectionOptions.urlContexts.)

Vassili answered 28/10, 2019 at 1:25 Comment(4)
still not working for me. when the app is closed. (swiped from the recent apps) the dynamic link opens the app but the url is nilBeisel
This answer seems outdated. The other answer about iterating over connectionOptions.userActivities worked for me.Phalanx
@Phalanx Looking at what I actually wrote, it seems to me that that's exactly what I say too: "look in the connectionOptions.userActivities". Iterating is how you look. I don't go into more detail because it all seems so obvious. :)Vassili
@Vassili Sorry! I just tried out the code block without reading your notes. :) You could just remove that...Phalanx
M
15

The accepted answer by Matt works for launching universal links when the app isn't already opened.

If you also want to handle universal links when the app is opened, you need both functions shown below:


// SceneDelegate.swift
// This function is called when your app launches.
// Check to see if our app was launched with a universal link. 
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
   // See if our app is being launched via universal link.
   for userActivity in connectionOptions.userActivities {
     if let universalLink = userActivity.webpageURL {
         // Do whatever you want with the universal link here.
         // NOTE: if you're navigating a web view, know that the web view will not be initialized here yet. 
         // To navigate a web view, store the URL in a variable and navigate to it once the web view is initialized.
     }
  }
}

// SceneDelegate.swift
// This function is called when your app is already running and a universal link to your app is clicked.
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    // Ensure we're trying to launch a link.
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
        let universalLink = userActivity.webpageURL else {
        return
    }

    // Handle the universal link here.
    // If you're navigating a web view, here's how I do it:
    //MyApp.webView.evaluateJavaScript("location.href = '\(universalLink)'")
}

I've verified this works for my app. See this Github thread for more details.

Mishandle answered 30/12, 2021 at 19:54 Comment(7)
thanks this one was the answer that worked for me!Housewifery
Hi! thanks for the answer! Could you please let me know how to call the webview from viewcontroller? I dont understand MyApp.webView.evaluateJavaScript("location.href = '(universalLink)'")Equality
@KhrisVandal It's been awhile since I was in this code. But I think webView is just a public variable on the MyApp type. You can check out our code here: github.com/pwa-builder/pwabuilder-ios/tree/main/…Mishandle
This is not working. When I tap a universal link and the app is running in background, scene(_:continue:) is supposed to get invoked with the universal link, but this method is not even invoked for me. Something else is required than just implementing this method?Marielamariele
Posted a separate question about the background scenario and have an answer.Marielamariele
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {} not getting called. The app gets opened, method not fired. Please help me to debug this issue.Incorporate
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) this method not firing anymore. Please help me to debug this.Incorporate
V
5

Apple responded confirming that issue in iOS 13.

Voiceful answered 28/10, 2019 at 1:11 Comment(2)
Do you have a link for the issue apple confirmed? The accepted answer does not work for me, when the app is closed and I click the dynamic link, the app opens but the url is nil.Beisel
is it fixed by now?Cheliform
F
5

This worked for me:

func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        for userActivity in connectionOptions.userActivities {
            if let url = userActivity.webpageURL { //ADD WHATEVER CONDITION YOU NEED
                //DO WHAT YOU NEED HERE
                break
            }
        }
    }

Basically the problem is that the universal link is "hidden" inside the connectionOptions so you have to search for it with the loop.

Ferrel answered 14/10, 2020 at 11:35 Comment(1)
This is not working any more.Equality
A
0

For anyone running into this using SwiftUI, the docs do not specify clearly that not all the lifecycle delegates are called.

To catch the universal link with SwiftUI, you have to use the view modifier onOpenURL like this:

var body: some Scene {
    WindowGroup {
        ContentView()
            .onOpenURL { url in
                print("Universal Link: \(url)")
                handleUniversalLink(url)
            }
    }
 }
Athletics answered 7/6 at 6:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.