33

In the info.plist file I configured URL Identifier and URL Scheme successfully. Also I am able to open the app using the custom URL. The problem is when the app launches for the first time, the method

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) 

does not get called.

I have some dependent functionality based on the above method. So when the app launches for the first time, I am not able to see anything in my app.

Also I added code in the method

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let _ = (scene as? UIWindowScene) else { return }
        
        let url = connectionOptions.urlContexts.first?.url
        
    }

but I get url as nil here.

However if my app is in background mode and I hit URL then above method calls successfully and dependent functionality working fine. Following is my code on scene(_:openURLContexts:) method in sceneDelegate.

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>){
        let url = URLContexts.first?.url
        let urlString: String = url!.absoluteString
        
        if let urlComponents = URLComponents(string: urlString),let queryItems = urlComponents.queryItems {
            queryParams = queryItems
        } else {
            print("invalid url")
        }
        
        guard let windowScene = (scene as? UIWindowScene) else { return }


        self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let rootVC = storyboard.instantiateViewController(identifier: "LocationViewIdentifier") as? UIViewController else {
            print("ViewController not found")
            return
        }
        let rootNC = UINavigationController(rootViewController: rootVC)
        self.window?.rootViewController = rootNC
        self.window?.makeKeyAndVisible()
    }

Can anyone tell me why first time above method does not call?

auspicious99
  • 3,902
  • 1
  • 44
  • 58
iPhone
  • 4,092
  • 3
  • 34
  • 58
  • 1
    What's the current status of this question? Did one of the answers solve your problem? If yes, please accept one of them. Do you need more help? If yes, can you explain what the provided solutions did to your problem and what's still missing? I'd be glad to help you out on this one – emmics Apr 28 '20 at 09:56

4 Answers4

33

Maybe this will help your situation.


func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
       
    let urlinfo = connectionOptions.urlContexts
    let url = urlinfo.first?.url as! NSURL
  
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext*h>) {
       
    let url = URLContexts.first!.url as NSURL

}

Update at 17.6.2021

If you wish to use Deeplink and Universal Link both this is my method.

    //Deeplink or Universial Link Open when app is start.
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
                
        // Universial link Open
        if let userActivity = connectionOptions.userActivities.first,
           userActivity.activityType == NSUserActivityTypeBrowsingWeb,
           let urlinfo = userActivity.webpageURL{
            
            print ("Universial Link Open at SceneDelegate on App Start ::::::: \(urlinfo)")
            
        }
        
        //deeplink Open
        if connectionOptions.urlContexts.first?.url != nil {
          let urlinfo = connectionOptions.urlContexts.first?.url
            
            print ("Deeplink Open at SceneDelegate on App Start ::::::: \(String(describing: urlinfo))")

          
        }
        
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    // Universial link Open when app is onPause
    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
            let urlinfo = userActivity.webpageURL{
            
            print ("Universial Link Open at SceneDelegate on App Pause  ::::::: \(urlinfo)")
            
        }
    }
    
    // Deeplink Open when app in onPause
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        
        let urlinfo = URLContexts.first?.url
        print ("Deeplink Open on SceneDelegate at App Pause :::::::: \(String(describing: urlinfo))")

    }

Thanks

Peterworks
  • 435
  • 4
  • 13
  • 2
    This worked for me in Oct 2020. willConnectTo is called on clean app launch and using " if let url = connectionOptions.urlContexts.first?.url {...." got me the deeplink URL appropriately – Steve B Oct 01 '20 at 23:20
  • 1
    This is sort of the right answer, but really light on details. To fill in the details a bit: When the app is launched on a cold start the openURLContexts function WILL NOT get called, even though the name implies that it will. You need to check why your app is connecting to a scene, and then perform actions that you would in the openURLContexts in the willConnect function. – Chad Oct 12 '20 at 14:11
  • 1
    Tiny little life saver! – Anticro Apr 09 '21 at 12:59
  • 2
    For me connectionOptions.urlContexts.first?.url is nil on cold start via deep link. – algrid Apr 30 '21 at 17:06
  • func scene(_ scene: UIScene, continue userActivity: NSUserActivity) is what helped me – Cherpak Evgeny Nov 15 '21 at 16:16
9

I think the Apple docs explain it most clearly, i.e.,

If your app has opted into Scenes, and your app is not running, the system delivers the URL to the scene(_:willConnectTo:options:) delegate method after launch, and to scene(_:openURLContexts:) when your app opens a URL while running or suspended in memory.

Hence, it would only call your scene(_:openURLContexts:) (i.e., the one with this signature: func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) in the question) when your app opens a URL while running or suspended in memory only.

Instead, when the app is launched the first time, it calls scene(_:willConnectTo:options:).

auspicious99
  • 3,902
  • 1
  • 44
  • 58
  • 2
    clearly the best answer, thanks for the link to the doc ! – floydaddict Jan 13 '22 at 10:31
  • Glad that you found it helpful! – auspicious99 Jan 13 '22 at 13:58
  • 1
    Great answer! But I find `scene(_:openURLContexts:)` is called in one of my app when it's launched by URL (the app wasn't running before that). I have same code in another app, but `scene(_:openURLContexts:)` isn't called in that scenario. From my search, there are other people observing the different behavior too. It's weird. – rayx Jan 11 '23 at 12:23
  • Really? haven't observed that, but maybe it could be a bug in iOS? Does that happen only for certain versions of iOS, etc.? – auspicious99 Jan 11 '23 at 18:38
  • @rayx is right. I have an app where openURLContexts is always called, even if the app was not launched. Tested on iOS 16.3 and 15.7.2. Could Apple have change this behavior? – vomi Feb 08 '23 at 11:13
  • @auspicious99 Sorry for the late replay (I didn't receive notification about your reply). Both of my apps are installed on my phone, which runs iOS 16.2. The only difference I can think of is that one app is created in XCode 13 and another in XCode 14, though I have no idea if that matters. From my search on the net, it seems not a new issue. See the last post in [this](https://developer.apple.com/forums/thread/134099?answerId=424542022#424542022) thread. – rayx Feb 08 '23 at 11:54
8

I had the same problem, and the method scene(_ scene:, continue userActivity:) was only called when the app is open.

When I checked the connectionOptions passed to the method scene(_ scene:, willConnectTo session, options connectionOptions:) it had a user activity with the expected URL. So, I ended up calling the first method manually:

func scene(_ scene: UIScene,
           willConnectTo session: UISceneSession,
           options connectionOptions: UIScene.ConnectionOptions) {

    if let userActivity = connectionOptions.userActivities.first {
        self.scene(scene, continue: userActivity)
    }
}
Hejazi
  • 16,587
  • 9
  • 52
  • 67
  • 2
    Is there a good solution for this, I am facing a related issue. And method suggested here by Hejazi did not work for me. – Michel Sep 12 '20 at 07:10
0

My situation was that the openURL extra function provided in the SceneDelegate was not being called after returning from Facebook Authentication.

The solution was using

.onOpenURL { (url) in
                ApplicationDelegate.shared.application(
                    UIApplication.shared,
                    open: url,
                    sourceApplication: nil,
                    annotation: [UIApplication.OpenURLOptionsKey.annotation]
                )
            }

To call the function in my extra application delegate, which then worked properly.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Jprofficial
  • 329
  • 3
  • 10