DEV Community

Filip Němeček
Filip Němeček

Posted on • Edited on

iOS 13: launchOptions always nil? This is the reason & solution

So 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 {
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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) {
}
Enter fullscreen mode Exit fullscreen mode

And this one to handle URL launch:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
}
Enter fullscreen mode Exit fullscreen mode

Once again, this is much better than prior to iOS 13 changes. 🙂

Thanks for reading!

Top comments (7)

Collapse
 
dksmarttech profile image
dk-smart-tech • Edited

@nemecek_f have you found an alternative for UIApplication.LaunchOptionsKey.location in the above case.

I'm monitoring significant location updates and the app is being launched but with nil launch options and in scendelegate ConnectionOptions doesnt have a proper alternative.

Collapse
 
nemecek_f profile image
Filip Němeček

Hi! Maybe it is hidden in connectionOptions.userActivities? But I havent used this personally. Kind of frustrating that Apple does not document this better.. I would expect some info in the docs but no - developer.apple.com/documentation/...

Collapse
 
dksmarttech profile image
dk-smart-tech

I'm coding right now as we chat here! I'm going with a workaround: I don't care the location key is nil or not every time the app is launched I do operations that I need. And I control it with an if-case and decide whether to actually do it nor not!

Very frustrating. I'm sure many apps are relying on the launch options!!

I will update here by the end of the day, what I end up doing.

Collapse
 
aledap profile image
Iqra Padela • Edited

@dksmarttech Hi, I am having the same issue. iOS 14.4.2.
Did you find a proper solution for this?

Collapse
 
isidar profile image
Nazarii Melnyk

I've found one particular case when it doesn't equal nil. It happens when the app is not launched and you do it by deeplinking. In that case, it contains a URL.

Collapse
 
nemecek_f profile image
Filip Němeček

Interesting! Thanks for the info but it is kind of strage, that this (possibly) one case is still in the AppDelegate

Some comments may only be visible to logged-in visitors. Sign in to view all comments.