Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)?

like image 257
Dmitry Avatar asked Oct 04 '19 22:10

Dmitry


4 Answers

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.)

like image 53
matt Avatar answered Oct 19 '22 14:10

matt


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.

like image 28
Judah Gabriel Himango Avatar answered Oct 19 '22 13:10

Judah Gabriel Himango


Apple responded confirming that issue in iOS 13.

like image 35
Dmitry Avatar answered Oct 19 '22 12:10

Dmitry


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.

like image 42
Nicola Salvaro Avatar answered Oct 19 '22 12:10

Nicola Salvaro