https://kotlinlang.org logo
#compose
Title
# compose
j

Joseph Hawkes-Cates

03/02/2023, 4:44 PM
I’ve added nested navigation to my app and everything is working great except this one scenario. We have a need to open internal deeplinks from a Uri that we get from our backend. The destination for this deeplink is defined within a nav graph in our nav host. When we open a deeplink from outside the app, the backstack looks like this:
root > destination nav graph (ng1) > Start destination (A) > deeplink destination (B)
. When I use
navController.navigation(deeplink=uri)
with navOptions to popUpTo the root nav graph,
A
is not inserted into the backstack behind
B
like it is with the external deeplinks.
👀 1
Is there some combination of NavOptions or Navigator.Extras that I can use to get the start destination to be injected?
I also tried using a PendingIntent which does work like I expect except it restarts the activity and shows the Splash screen very quickly
m

mgrazianodecastro

03/02/2023, 4:46 PM
Following this tread because I want to know the answer too
(my junior spirit would probably just handle deep link launchers with a different set of logic)
j

Joseph Hawkes-Cates

03/02/2023, 4:48 PM
I think, maybe, I could solve this by making A it’s own nav graph and then making B a nested destination within it, but I’m not sure if I can make a nav graph the starting destination of another nav graph
m

mgrazianodecastro

03/02/2023, 4:50 PM
hmm maybe you could check if nav A was opened by a deep link. If so, create a new stack of navigation? I'm just guessing
I can see how this doesn't scale well in multi module projects, when one module doesn't know about others
j

Joseph Hawkes-Cates

03/02/2023, 4:56 PM
I’ve also tried creating an Intent with the deeplink uri as the data and calling
navController.handleDeepLink(intent)
and this gets the backstack in the state I expect, but it still shows the splash screen
yeah, I’d like to avoid examining the backstack and doing like manual two step navigations or something like that
d

dazza5000

03/02/2023, 5:11 PM
i don't know the answer to your specific question, but have you read this https://developer.android.com/jetpack/compose/navigation#deeplinks
j

Joseph Hawkes-Cates

03/02/2023, 5:11 PM
yeah
it suggests using pendingIntent which shows the splash screen in this case which I don’t want
it appears the behavior of
navController.navigate(deeplink = uri)
is as designed: https://issuetracker.google.com/issues/154760276
which makes sense
I guess my question becomes: Is there a way to navigate to the deeplink with a PendingIntent without showing the splash screen?
m

mgrazianodecastro

03/02/2023, 5:33 PM
maybe splash screen is showing because the app hasn't been loaded to memory yet?
j

Joseph Hawkes-Cates

03/02/2023, 5:38 PM
nah. I’m opening this link from within the app. So the app is definitely in memory
d

dorche

03/02/2023, 6:14 PM
Isn't that launching a new activity just hence why it works but you see the splashscreen? Edit: actually you still shouldn't see the splashscreen so I'm wrong I think this needs to be "fixed" on nav graph/component level but if you really wanna go that route you probably need to look at launchMode and onNewIntent (imo this approach is bad and you don't want to be launching new activities at all)
j

Joseph Hawkes-Cates

03/02/2023, 6:16 PM
Yeah, I definitely don't want to launch a new activity but it seems to be the only way I can get the nav controller to fill in the start destination of my graph for me
I may have to just back fill it myself
d

dorche

03/02/2023, 6:32 PM
From the user's point of view, what should happen when they press back on your destination screen, where do they land?
j

Joseph Hawkes-Cates

03/02/2023, 6:32 PM
I want them to land on destination A when they go back from destination B.
d

dorche

03/02/2023, 6:35 PM
Would that mean that the user is brought "back" to a screen they never visibly visited? Perhaps nav component is trying to guard against such UX exactly?
j

Joseph Hawkes-Cates

03/02/2023, 6:38 PM
It does mean that they could be brought back to a screen they haven't visited yet but the navigation docs specifically state that artificially filling in the start destination of a graph on the backstack when navigating to a deeplink is supported and it works that way if the same link is opened from outside the app.
So I was trying to replicate that behavior in this situation.
d

dorche

03/02/2023, 6:47 PM
Just from memory of the old fragment safe navigation plugin - I think it wouldn't let you navigate to a destination that is on a different nav graph, other than the start destination of said other graph Needs to be double checked, I might be wrong about this
j

Joseph Hawkes-Cates

03/02/2023, 9:57 PM
I was able to make this work how I needed to by doing the following with my deeplink URI inside my app:
Copy code
val deepLinkMatch = navController.graph.matchDeepLink(NavDeepLinkRequest(deepLinkUri, null, null))
                if (deepLinkMatch != null) {
                    val graphStartRoute = deepLinkMatch.destination.parent?.startDestinationRoute
                    val deeplinkMatchRoute = deepLinkMatch.destination.route
                    var backstackPopped = false

                    // If the deeplink is not the start of its graph, we need to put the start destination on the backstack
                    // This only handles a single level of nav graph nesting so a nav graph nested
                    // within a nav graph may not work as intended.
                    if (graphStartRoute != null && graphStartRoute != deeplinkMatchRoute) {
                        navController.navigate(
                            graphStartRoute,
                            navOptions {
                                popUpTo(RootNavGraph.route)
                            }
                        )
                        backstackPopped = true
                    }
                    navController.navigate(
                        deepLinkUri,
                        navOptions {
                            launchSingleTop = true
                            if (!backstackPopped) {
                                popUpTo(RootNavGraph.route)
                            }
                        }
                    )
only handles a single level of nested nav graphs, but that is good enough for my needs right now.
409 Views