2

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 use navController.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
                    }
                }
            )
        }
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Francisco Durdin Garcia
  • 12,540
  • 9
  • 53
  • 95
  • Hi there. Couple of comments that might help you. 1. navController.graph.matchDeepLink has @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) so you will have problems with using it. 2. I think your popUpTo logic removes your startDestination from back stack or you navigate to quick 3. You might want to wait for any pending navigation. You can save somewhere your pending deep link uri then you can add NavController.OnDestinationChangedListener to listen for destination changes, then if app arrives at right destination you might want to call navController.navigate – MrOnyszko Feb 14 '23 at 16:41

0 Answers0