How to Implement Deep Link and ShortcutItems When Using SceneDelegate

So the App I am working on support multi-window by implementing UISceneDelegate.

This all went well until one day I realize 3d touch shortcut items and universal links does not work when App is cold launched.

It takes a while for me to realize that the system callback scene:openURLContexts: is not called when cold Launch App.

Both of the following callbacks are not called for cold launch but called when App is already in background.

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void)

The strangest thing is, their counterparts in AppDelegate are called correctly both for cold launch and warm launch:

func openURL(_ url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool
func performActionForShortcutItem(_ shortcutItem: UIApplicationShortcutItem, completionHandler: ((Bool) -> Void)?)

Then I make a quick demo and confirm what Apple said in its documentation.

So in iOS 13, the correct way to handle open url and shortcut items is to store these items in scene(_:willConnectTo:options:) then perform these actions in sceneDidBecomeActive.

func scene(_ scene: UIScene,
           willConnectTo session: UISceneSession,
           options connectionOptions: UIScene.ConnectionOptions) {
    tempSceneLaunchOptions.urlContexts = connectionOptions.urlContexts
    tempSceneLaunchOptions.userActivities = connectionOptions.userActivities
    tempSceneLaunchOptions.shortcutItem = connectionOptions.shortcutItem
}

func sceneDidBecomeActive(_ scene: UIScene) {
    // This is demostrated in Apple's example:
    // https://developer.apple.com/documentation/uikit/menus_and_shortcuts/add_home_screen_quick_actions
    if let urlContexts = tempSceneLaunchOptions.urlContexts, !urlContexts.isEmpty {
      scene(scene, openURLContexts: urlContexts)
      tempSceneLaunchOptions.urlContexts = nil

    }
    else if let userActivity = tempSceneLaunchOptions.userActivities?.first {
      scene(scene, continue: userActivity)
      tempSceneLaunchOptions.userActivities = nil
    }
    else if let shortcutItem = tempSceneLaunchOptions.shortcutItem {
      performShortcutItem(shortcutItem: shortcutItem, completionHandler: nil)
      tempSceneLaunchOptions.shortcutItem = nil
    }
}
Posted 2020-03-17

More writing at jakehao.com

Discussions on Twitter