Simplifying iOS App Invocation Handling with Swift: A Comprehensive Guide

Ashwani Kumar
3 min readSep 13, 2023

--

In the world of mobile app development, understanding how your app is launched and invoked is crucial for providing a seamless user experience. iOS apps can be opened in various ways, such as from a deep link, a notification click, or simply tapping the app icon. In this article, we’ll explore how to determine the app’s entry point using Swift, and we’ll introduce a practical use case to illustrate the concept.

The AppInvocationType Enum

Let’s start by defining an AppInvocationType enum that represents the different ways your iOS app can be invoked:

enum AppInvocationType {
case deepLink(url: URL)
case notification(userInfo: [AnyHashable: Any])
case appIconClick
case unknown
}
  • deepLink(url: URL): The app is invoked via a deep link with a specific URL.
  • notification(userInfo: [AnyHashable: Any]): The app is opened in response to a notification click, and it receives user info associated with the notification.
  • appIconClick: The app is launched by tapping its icon on the home screen.
  • unknown: The app is opened in an unknown manner.

The GetAppInvocationTypeUseCase Class

To determine the app’s entry point and return the appropriate AppInvocationType, we can create a GetAppInvocationTypeUseCaseclass:

class GetAppInvocationTypeUseCase {
private let userActivityKey = "UIApplicationLaunchOptionsUserActivityKey"
private let launchOptions: [UIApplication.LaunchOptionsKey: Any]?

init(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
self.launchOptions = launchOptions
}

func invoke() -> AppInvocationType {
guard let launchOptions = launchOptions else { return .appIconClick }

if let dictionary = launchOptions[UIApplication.LaunchOptionsKey.userActivityDictionary] as? [AnyHashable: Any] {
guard let url = (dictionary[userActivityKey] as? NSUserActivity)?.webpageURL else { return .unknown }
return .deepLink(url: url)
}

if let userInfo =
launchOptions[UIApplication.LaunchOptionsKey.remoteNotification] as? [String: AnyObject] {
return .notification(userInfo: userInfo)
} else if launchOptions[UIApplication.LaunchOptionsKey.sourceApplication] == nil {
return .appIconClick
} else {
return .unknown
}
}
}

Key Components Explained:

  • Initialization: The init(launchOptions:) method initializes the use case with the provided launchOptions dictionary, typically passed to application(_:didFinishLaunchingWithOptions:) in the AppDelegate.
  • invoke() Method: This method serves as the primary entry point for determining how the app was launched. It returns an AppInvocationType enum, indicating the app's launch type.
  • Deep Link Handling: The code begins by checking for the presence of a deep link. It examines the userActivityDictionary within launchOptions, ensuring it's a browsing web activity. If validated, it extracts the URL and returns .deepLink(url:).
  • Notification Handling: Next, it assesses whether a remote notification payload is present. If found, it returns .notification(userInfo:) with the associated user info.
  • App Icon Click: If none of the previous conditions apply, the code verifies if sourceApplication is nil, signaling that the app was launched by tapping its icon. In this scenario, it returns .appIconClick.
  • Unknown: If none of the conditions align, the method returns .unknown to denote an unrecognized app invocation.

Practical Use Case

Now, let’s explore a practical use case for this code. Imagine you have a news app that supports deep linking. Users can open articles directly from external links. You want to determine how users accessed your app so you can provide a tailored experience.

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

let getAppInvocationTypeUseCase = GetAppInvocationTypeUseCase(launchOptions: launchOptions)
let invocationType = getAppInvocationTypeUseCase.invoke()

switch invocationType {
case .deepLink(let url):
print("App was invoked from a deep link. URL: \(url.absoluteString)")
// Handle deep link URL

case .notification(let userInfo):
print("App was invoked from a notification click. UserInfo: \(userInfo)")
// Handle notification data

case .appIconClick:
print("App was invoked from the app icon.")
// Handle app icon click

case .unknown:
print("App was invoked in an unknown manner.")
}

return true
}

// Other AppDelegate methods...
}

In this use case, you’re using the GetAppInvocationTypeUseCase class to determine the app's entry point. Based on the invocation type, you can customize the user experience. For example, when the app is opened from a deep link, you can directly display the linked article. When opened from a notification, you can show the relevant news story.

Conclusion

Understanding how your iOS app is invoked is essential for building user-friendly experiences. By implementing the AppInvocationType enum and the GetAppInvocationTypeUseCase class, you can efficiently determine the app's entry point and tailor your app's behavior accordingly. This knowledge allows you to provide a seamless and context-aware user experience, enhancing user engagement with your app.

If you found this article helpful and informative, please consider giving it a round of applause or claps to show your appreciation! Your feedback and support are greatly valued. Thank you for reading! 👏👏👏

--

--