Summary
The issue at hand is related to deep linking in an iOS app, where clicking a deep link when the app is in the background or has been killed results in the target screen opening without the tab bar and navigation bar. This is in contrast to when the app is in the foreground, where deep links work as expected, preserving the navigation stack.
Root Cause
The root cause of this issue can be attributed to several factors:
- Incorrect handling of the app’s state when it is launched from a deep link while in the background or after being killed.
- The way the window scene and root view controller are managed during the app’s launch process.
- The routing logic in the
DeepLinkManagerclass, specifically how it presents view controllers and handles the navigation stack.
Why This Happens in Real Systems
This issue occurs in real systems due to the following reasons:
- App state management: When an app is launched from a deep link while in the background or after being killed, the system may not properly restore the app’s previous state, leading to inconsistencies in the navigation stack.
- Scene delegate methods: The
scene(_:, willConnectTo:, options:)method in theSceneDelegateclass may not be called as expected when the app is launched from a deep link, affecting how the window scene and root view controller are set up. - View controller presentation: The presentation style and modal presentation of view controllers can affect how the navigation stack is displayed, especially when the app is launched from a deep link.
Real-World Impact
The real-world impact of this issue includes:
- Poor user experience: Users may become confused or frustrated when the app’s navigation stack is not preserved, making it difficult for them to navigate the app.
- Increased support requests: Users may contact support due to issues with deep linking, resulting in increased support requests and potential negative reviews.
- Loss of engagement: A poor user experience can lead to decreased user engagement and retention, ultimately affecting the app’s overall success.
Example or Code
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Properly handle the app's state when launched from a deep link
if let userActivity = connectionOptions.userActivities.first(where: { $0.activityType == NSUserActivityTypeBrowsingWeb }) {
DispatchQueue.main.async {
DeepLinkManager.shared.handle(userActivity: userActivity)
}
}
}
// Update the DeepLinkManager routing code to properly handle the navigation stack
private func routeToViewController(viewController: UIViewController) {
// Ensure the tab bar and navigation bar are visible
if let tabBar = UIApplication.shared.keyWindow?.rootViewController as? UITabBarController,
let nav = tabBar.selectedViewController as? UINavigationController {
// Push the view controller onto the navigation stack
nav.pushViewController(viewController, animated: true)
} else {
// Present the view controller modally if the tab bar and navigation bar are not available
let navVC = UINavigationController(rootViewController: viewController)
navVC.modalPresentationStyle = .fullScreen
UIApplication.shared.keyWindow?.rootViewController?.present(navVC, animated: true)
}
}
How Senior Engineers Fix It
Senior engineers fix this issue by:
- Properly handling the app’s state when launched from a deep link, ensuring that the navigation stack is preserved.
- Updating the routing logic in the
DeepLinkManagerclass to correctly handle the presentation of view controllers and the navigation stack. - Testing the app thoroughly to ensure that deep links work as expected in all scenarios, including when the app is in the background or has been killed.
Why Juniors Miss It
Junior engineers may miss this issue due to:
- Lack of experience with deep linking and app state management.
- Insufficient testing of the app’s behavior when launched from a deep link.
- Incomplete understanding of how the navigation stack is managed in iOS apps, particularly when using tab bars and navigation controllers.