iOS 13: launchOptions always nil? This is the reason & solution
launchOptions have moved and you find them in AppDelegate no longer.
Published: May 22, 2020 Sponsored See booksSo today I spent quite some time puzzling over why I was always getting nil
launchOptions
argument in func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
and then finally found a solution.
The reason
The culprit is the new project structure for iOS 13 and above. In the past we were used as AppDelegate
as the only class to handle app lifecycle events and responding to shortcuts, URL schemes and what not.
But with iOS 13 and more specifically iPadOS came the push to better support multiple screens for apps we got the SceneDelegate
where most of the events now moved.
So even though the didFinishLaunchingWithOptions
still looks the same:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
}
You don't get any launchOptions
here. It would be better if Apple simply changed the signature but for some reason (lets hope there at least is a reason) the argument is still present but always nil
.
The solution
The solution to correctly getting launchOptions
in iOS 13 and above is
to use SceneDelegate
and the willConnectTo session
which is automatically there with some basic code.
The full signature looks like this:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
And the connectionOptions
is new "reincarnation" of the trusty old launchOptions
. To be fair to apple, this is much better to work with.
Say you want to respond to launch from shortcut item (the quick action available with long press on app icon). Previously you would have to reach into the options dictionary and do a cast.
Now it looks like this:
if let shortcut = connectionOptions.shortcutItem {
// handle shortcut here
}
What about reacting to URL scheme? We have urlContexts
set available and can simply pull the first item for basic implementation:
if let firstUrlContext = connectionOptions.urlContexts.first {
// handle firstUrlContext.url
}
And that is it!
Hope this will save you some time when implementing this and you won't have to go full Sherlock 🕵 finding what is wrong...
One last thing
Since I have shown you how to react to shortcuts and URLs, let's see how to do these tasks when app is already running in the background.
We have this method to handle shortcuts:
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
}
And this one to handle URL launch:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
}
Once again, this is much better than prior to iOS 13 changes. 🙂
Thanks for reading!
Uses: Xcode 11 & Swift 5