Another compose-navigation question... What's a re...
# compose
c
Another compose-navigation question... What's a reasonable away to avoid having a 'conditional start destination' when an app has login or onboarding? I've used different activities to achieve this in the past. However, now I am working in a single activity compose multiplatform app, so I'm not sure how to work around that anymore 🤔
Does it make sense to have two different nav hosts/controllers that are chosen based on some top level state (isLoggedIn, hasOnboarded, etc.) ?
s
Keep your normal start destination, and you can do something like keep the splash screen on while you're still evaluating if you want to login or do onboarding. If you evaluate that as true, navigate to your login/onboarding while popping the entire backstack.
☝🏿 1
Probably don't want to use many NavHosts, you're gonna break all deep links, predictive back handlers etc.
☝🏿 1
v
On Android - I was using an IF changing the start destination to change what is shown and relied on the splashscreen lib to hide whatevers happening until it's loaded. Once moved to KMP, single activity + iOS + Wasm targets, I've introduced an interim "splash" route, which is the only start destination of the only
NavHost
in the application. I think that's your best option. EDIT: I still rely on the Android splashscreen lib, but it's just hiding the empty "splash" route now. Also, when I know my actual start destination - I navigate to it popping up to "Splash" in an inclusive manner (so it's gone from the stack).
s
Yeah definitely don't do that. Follow this thread and the links by Ian Lake https://kotlinlang.slack.com/archives/CJLTWPH7S/p1691095853617739?thread_ts=1691095853.617739&cid=CJLTWPH7S which all day you shouldn't do that
v
Nah, I don't agree that adding a Splash route is bad for CMP. I completely agree for plain ol' Android, I actually do find adding an interim Splash route a bad practice on Android. But, without a Splash route - your start route might/will appear when building on iOS or especially Wasm/JS, because they don't have a core splashscreen implementation that Android has that you can delay until you're ready. With iOS I found that - you have a LauncherScreen storyboard or w/e to show the splash until your UIViewController that shows the Compose app loads, then it closes - that's it. And when it loads - you will have to show something. Also, when changing start destinations on iOS, I noticed that in some cases a crash might just occur, for the whole nav graph does not always get initialised in time for a navigation action. So, on iOS - there might be some finnicky way to delay the removal of the launch screen On Wasm/JS - also it's doable, but I found it rather problematic for no reason
s
If you put a splash screen as your start destination, after you've deep linked somewhere, when you do navigateUp the splash screen will again be added to your backstack.
c
Interesting... seems like no perfect option 🤔 Having a splash screen route messes up back nav from deeplinks. Using a normal/usual route as the start destination and navigating immediately to login has issues with nav graph initialisation on other platforms.
thinking about it some more... @Vidmantas Kerbelis Instead of using a splash composable as the first destination, you could wrap the first actual destination in an if/else block that either shows the splash composable or normal screen composable. From there we can navigate to the login/onboarding if needed. Thereafter the actual content gets shown on the first destination instead of the splash wrapper. Best I can think of so far... 😅
v
Well, in my case that "Splash" destination is basically a meaningless nav destination and is just a placeholder until the actual start destination loads. The point is to never show it and pop it immediately as you know where to go. For deeplinks - I'm not using the NavGraph's
deeplink
NavDestination's, I handle all deeplinks via the main view model and passing them to an event bus. In my eyes - it's much simpler as you can handle the same deeplink in whatever way you want, on whatever screen you want, or even multiple screens. And so, a deeplink would: • Load up the app • On Android it would show the splashscreen overlay, with the current default target nav destination as
Splash
• In the main view model - fIgure out what to show in accordance to the received deeplink • In the main view model - navigate to where the user needs to be + pop the splash destination in an inclusive manner • Hide the Android splashscreen overlay
s
Do you handle creating a synthetic backstack yourself manually after someone has deep linked to your app, and then presses the top-left button to do navigateUp? https://developer.android.com/guide/navigation/principles#the_up_button_never_exits_your_app
v
Yeah, in some cases I do create an appropriate back stack, as if the user navigated to that screen.
s
Specifically at the moment they press the top-left button? And if they press the system back, do you let them go back to the app they came from?
v
Top left buttons are all controlled by me -> they usually just pop the back stack. The system back just works correctly out of the box (w/o any custom BackHandler's added). In both cases, you do properly go back to the app you came from after a deeplink.
s
You shouldn't go back to the app you came from when pressing the top-left back button
v
Anyway, I'm not understanding what you're trying to get at, or maybe I'm misunderstanding some statements that you're making. But in general - all of the navigation works as a user would expect. I don't really see what you're trying to nitpick me about
s
I am not trying to nit-pick anything. I am trying to understand if with your setup, you're following the rule specified here https://developer.android.com/guide/navigation/principles#the_up_button_never_exits_your_app You said "In both cases, you do properly go back to the app you came from after a deeplink." which makes me think that you do not do this right. Since you actually should not go back to the app you came from if you were just deep linked into and the user pressed the up button.
v
Pressing the top back button mostly just does popBackStack, so it works as a back action, dunno.
s
Well, the documentation I linked clearly states otherwise. And no, it does not "mostly do popBackStack", it should specifically do navigateUp, which specifically has a different behavior when you were deep linked into the app. All of this, to point out the fact that androidx.navigation handles all of this for you. As long as you call navigateUp properly, and you do not have your splash screen as your start destination, which is simply the wrong way to use this specific library.