Luna Debb
Luna Debb

Reputation: 69

Opening content from URL Scheme when App is closed

My issue

I'm implementing URL Schemes in my application and they're overall working fine when the app is in the foreground or the background. However, I've noticed that when it is completely closed and another app tries to access content using my URL (eg. app:page?image=1 ) which would normally work, it just opens the app but the content is never caught.

My Approach

I've set up code in both my AppDelegate and SceneDelegate methods

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:])

And

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

Desired behavior

It opens when the app is in the background, foreground or closed

Actual behavior

It only opens when in foreground or background

Upvotes: 3

Views: 3790

Answers (3)

tikamchandrakar
tikamchandrakar

Reputation: 92

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

    // Since this function isn't exclusively called to handle URLs we're not going to prematurely return if no URL is present.
    if let url = connectionOptions.urlContexts.first?.url {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            // Call your method here 
            self.handleURL(url)
            }

    }
}

Upvotes: 0

Mutawe
Mutawe

Reputation: 6524

To handle incoming URLs we simply call this function in both the scene(_:willConnectTo:options:) and the scene(_:openURLContexts:) delegate methods:

If the App is closed:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let _ = (scene as? UIWindowScene) else { return }
    
    
    // Since this function isn't exclusively called to handle URLs we're not going to prematurely return if no URL is present.
    if let url = connectionOptions.urlContexts.first?.url {
        handleURL(url: url)
    }
}

If the app is in background or foreground

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    // Get the first URL out of the URLContexts set. If it does not exist, abort handling the passed URLs and exit this method.
    guard let url = URLContexts.first?.url else {
        return NSLog("No URL passed to open the app")
    }


    
    handleURL(url: url)
}

You can revert to the following article for more about scene delegate and URL Schemes: Custom URL Schemes in iOS

Upvotes: 5

Swapnil Luktuke
Swapnil Luktuke

Reputation: 10475

Since your app is currently not running, it will be launched with those launch options. i.e. those options will be passed to willFinishLaunchingWithOptions: / didFinishLaunchingWithOptions: instead. Add you code to one of these methods.

For more information, read documentation about how to Respond to the Launch of Your App, or, more specifically Determine Why Your App Was Launched.

EDIT:

As commented by @paulw11 below, scene delegate works differently, and must be handled separately.

However, in Respond to Scene-Based Life-Cycle Events section, the last point is:

In addition to scene-related events, you must also respond to the launch of your app using your UIApplicationDelegate object. For information about what to do at app launch, see Responding to the Launch of Your App

So I assume, we still need to handle launch in willdidFinishLaunchingWithOptions / didFinishLaunchingWithOptions.

Upvotes: 2

Related Questions