1

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

Luna Debb
  • 49
  • 7

2 Answers2

4

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

Mutawe
  • 6,464
  • 3
  • 47
  • 90
2

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.

Swapnil Luktuke
  • 10,385
  • 2
  • 35
  • 58
  • 1
    Also, be aware that if you have adopted the newer `SceneDelegate` approach then the options are passed to your scene delegate, not your application delegate – Paulw11 Apr 29 '20 at 23:16
  • @Paulw11 thanks for that input. I have not used scenes yet. However, in [Respond to Scene-Based Life-Cycle Events](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle) 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 `will/did didFinishLaunchingWithOptions`, which is the missing part in OP's problem. – Swapnil Luktuke Apr 29 '20 at 23:32
  • 1
    Yes, you still need an app delegate, but if you have implemented the scene delegate then the `NSUserActivity` is not delivered to your app delegate on iOS13. If you are supporting earlier versions of iOS and have a scene delegate then you need to handle the activity in both places – Paulw11 Apr 30 '20 at 00:05
  • Brilliant answer! This logic applies to Universal Links as well: `scene(_:continue:)` is not invoked on cold app launch, and related `UserActivity` is passed to `scene(_:willConnectTo:options:)`, in `options.userActivities`. – Cemen Nov 09 '20 at 15:33