I'm recently struggling with some complex logic for deeplink & navigation management with Jetpack Compose Navigation. My actual problem is that when I handle my deeplinks and call navController.navigate(uri)
the navigation is working properly but the startDestination screen from the graph is never added to the stack.
So it's created as:
- Actual: Deeplink arrives > Deeplink Screen
- Expected: Deeplink arrives > Open Home > Deeplink Screen
My Home screen is the startDestination of the graph where Deeplink Screen belongs to.
Some important notes:
- I can't use
navController.handleDeeplink
because I'm doing my own deeplink management and this one doesn't work well with dynamic links (Firebase) or external web URIs. For this reason I always usenavController.navigate(uri)
- This solution is a workaround but I don't want to use it because I'm looking for a generic solution to work with nested graphs. Not a huge
when
clause. It's weird that compose don't support a synthetic stack and this is the "best" workaround. So possibly I'm missing something. - I don't want to copy/paste and re-implement the NavController. This is a solution as well but a disgusting one.
I'm attaching the code where I call my navigate method with the navOptions
. But it's more a theory question about Jetpack compose or what I could be missing from the library:
LaunchedEffect(pendingDeeplinkUri.value ) { // Avoid multiple executions using the intent as key
pendingDeeplinkUri.value?.let { uri ->
Timber.d("[DeepLinkManagement] LaunchedEffect pendingDeeplink $uri")
if (navController.graph.hasDeepLink(uri)) { //Check that deeplink exist
//find it in the graph
val match = navController.graph.matchDeepLink(NavDeepLinkRequest.Builder.fromUri(uri).build())
val destination = match!!.destination
navController.navigate(uri,
navOptions {
val changingGraphs = navController.graph.hierarchy.none { it == destination.parent }
Timber.d("[DeepLinkManagement] Changing graphs $changingGraphs")
if (changingGraphs) {
// If we are navigating to a 'sibling' graph (one that isn't part
// of the current destination's hierarchy), then we need to saveState
// to ensure that each graph has its own saved state that users can
// return to
Timber.d("[DeepLinkManagement] Parent ${destination.parent}")
popUpTo(destination.parent?.findStartDestination()?.id ?: 0) {
saveState = true
inclusive = true
}
// Note we specifically don't call restoreState = true
// as our deep link should support multiple instances of the
// same graph in a row
}
}
)
}
}
}