Hi, I have an issue with compose navigation that I...
# compose-android
s
Hi, I have an issue with compose navigation that I can't figure out. I want to add deeplink support to my app using compose navigation. I use a custom schema, and I've added the schema and host inside the manifest. I have set up everything like the docs say and it works fine when I push a notification that has an intent inside. The issue rises when I want to navigate to my deeplink from a web page by clicking a button. I set location.href to to this. The app launches but it does not go to the destination. Is this behavior caused by the fact that I'm calling a deeplink from the browser, or something else?
s
run from your terminal:
Copy code
adb shell am start -a android.intent.action.VIEW -d "your.link.here"
In order to test your deep link without whatever influence you think your browser has. If it does not work like this either, then it's a different issue.
s
This has the same issue, the app launches but it does not go to the destination.
s
Then you haven't setup the deep linking properly in some way. It's practically impossible to know what the issue is without more information. If your project is complex, try creating a new simple project and only add deep linking to it by following the documentation.
s
You're right, thanks.
😊 1
I got some clues while testing different launchModes. When using standard mode, everytime the deeplink is called, a new instance of activity is created, everything is ok. But when using singleTop for example, instead of creating a new instance, the previous is called with onNewIntent, this is where the problem seem to be.
s
If you don't use the default launch mode, then in your onNewIntent you need to forward that intent to your NavController.
πŸ‘ 2
i
As per the docs: https://developer.android.com/guide/navigation/design/deep-link#handle
It is strongly recommended to always use the default launchMode of standard when using Navigation. When using standard launch mode, Navigation automatically handles deep links by calling handleDeepLink() to process any explicit or implicit deep links within the Intent. However, this does not happen automatically if the Activity is re-used when using an alternate launchMode such as singleTop. In this case, it is necessary to manually call handleDeepLink() in onNewIntent(),
thank you color 1
πŸ‘ 2
πŸ‘ 2
s
Fixed it. Thanks.
d
Isn't this recommendation a bit misleading in some cases Ian? i.e. a lot of apps would be taking payments via a web journey (so you start some of the journey in the app but eventually use a custom chrome tab to handle the card payment). Then when the user pays with a card, you'd get a deep-link back to your app and if your launch mode is stardard then you'd get a new activity, instead of the user being navigated away from the custom tab in your existing activity?
s
@dorche This is exactly the scenario that I'm dealing with. It seems wrong to me too.
s
Can you intercept links clicked/sent inside your custom chrome tab to take over the deep linking before it is sent to the system?
d
I don't think you can, at least not without running into other edge cases and problems. An easy example is the fact that the user can always just click the Menu icon on a Custom Tab and "Open in browser", which then takes them fully out of your control as they'd be in Chrome (for example) and you're back to just waiting for the deep-link
I don't think there's anything wrong with it Shahryar, imo you just want
singleTop
launchMode in these cases and then handle the incoming deep-link. I'm just saying that I don't agree with the documentation and that it's misleading for one of the most common use cases for deep-links.
s
If they exit your app and are in chrome entirely I don't see what the issue is. You are then in the scenario where you will need to handle a generic deep link as if they never came from your app, that should be handled regardless of where they came from.
d
The issue is that when the user clicks "Open in browser", your app and activity isn't killed, it just goes in the background, right? So when you get a deep-link from Chrome, if you have
standard
you'd get a new activity which at the very least is very ugly UX (and some other caveats like that)
s
Yes it would be a new instance, but why is that a problem in that scenario? What if the app was killed in the meantime while you were in that chrome browser? Your app should be able to handle that case regardless. For the scenario when you are inside the app still and in the custom chrome tab then I can understand this being awkward, and I am not sure how you should do that since I've never done it myself. If there's a way to intercept a link it'd be easy since you can forward that to the NavController, but I don't know if you can do that.
d
Because then you'd have 2 instances of your app, in 2 separate tasks so they will both appear in Recents/Task menu on the phone, this in my opinion is quite clunky and ugly for the user. The solution to this is pretty easy - launchMode should be singleTop and you should handle the new intent in onNewIntent(). I'm not suggesting that it's hard to implement, just saying that I don't agree with the docs "strong recommendation".
πŸ‘ 1
Forwarding to the nav controller should be as easy as calling
Copy code
navController.navigate(intent.data)
or
Copy code
navController.handleDeepLink(intent)
From either
onNewIntent
or via your own listener with
addOnNewIntentListener
πŸ‘ 1
πŸ™ 1
s
How should I get a reference of navController outside of my main Composable? I'm using this currently:
Copy code
val bottomSheetNavigator = rememberBottomSheetNavigator()
val navController = rememberNavController(bottomSheetNavigator)

ModalBottomSheetLayout(bottomSheetNavigator) {
        NavHost(
            navController = navController,
            ...
        ) {}
s
i
Or bring the new Intent into composition by relying on
LocalActivity.current as OnNewIntentProvider
(which always succeeds if you are in a
ComponentActivity
) along with
DisposableEffect
to call `addOnNewIntentListener`/`removeOnNewIntentListener` - that way your composable gets the callback directly rather than having to write any code in your activity at all
πŸ™Œ 3
πŸ™ŒπŸ½ 1
πŸ‘€ 1
c
@Shahryar Khosravi you should write a blog post about this πŸ˜… I work on a ton of different apps and some of them do legitimately seem like they should only have a single instance of it, and so knowing how to deep link in that case would be super helpful. please do share your journey!