Open Composables via notification with Jetpack Navigation
Handling screen navigation is a complex task in any framework. Luckily we already have a great tool for helping in this flow, but some different scenarios may need more attention. One of these scenarios is opening the application on a specific Composable in Jetpack Compose.
The Jetpack Navigation Compose is an awesome tool: it uses a solid base from the default Jetpack Navigation for View System with the flexibility needed to handle Composable.
When developing the Navigation Graph in this new library, we create a Composable function similar to this one below, informing the destinations and arguments to navigate in our application. For more information on how to get started with Jetpack Navigation Compose, please access the official docs.
Back to the View System Jetpack Navigation, when creating PendingIntent
for notifications, the code was similar to:
However, as we can notice, the code from our Navigation Graph migrated from XML to Kotlin and some of the parameters (like graph and destinations ids) passed to NavDeepLinkBuilder
do not make sense anymore.
For more information about PendingIntent
, please access the clarifying article by Nicole Borrelli.
Deep links to the rescue
The library supports implicit deep links to help the navigation between Composables, associating a specific URL, action and/or mime-type. In order to add this support to our Composable, we add a new parameter to it, deepLinks
:
In the example above, we created a simple URI (https://example.com
) and concat a subdirectory (/task_id=
) to open the screen in a specific task, based on the id parameter ({task_id}
).
Now, we have two alternatives on how to handle the deep link call in our notification.
Set the ComponentName to the Activity in the Intent
The first alternative is to set the Activity in the ComponentName
when creating the Intent
. This will link the URI that we are passing in the Intent
with the Activity containing our Navigation Graph.
This is a nice approach when the notification and the Activity containing the Navigation Graph are in the same module. If they are separate or do not have the visibility needed, then we have a second alternative.
Add an intent-filter to match the deep link
In case the Activity and the notification code are not in the same module, we can add a proper intent-filter
to match our deep link declared in the Navigation Graph.
After declaring the intent-filter
in the AndroidManifest.xml
, the notification code can create our PendingIntent
similar to:
This time we do not set the Context
and the Activity, because the intent-filter
will handle this communication for us.
How to test the deep links
Deep link needs to be well defined in order to work. If you have some issues (like I did), I suggest using Android Device Bridge to validate if the deep link is correctly set before integrating in your notification, which usually is harder to test multiple times.
In order to test your deep link and intent-filter
, run the following command:
adb shell am start -W -a android.intent.action.VIEW -d “https://example.com/task_id=35”
Running this command will open the Composable that we registered earlier with this deep link. If it does not work or open the start destination, probably something needs to be updated.
For more information about deep links in Android, please access the official docs.
Final thoughts
It is great to already have a tool as powerful as Jetpack Navigation Compose in the beginning of Jetpack Compose. It allows navigation handling in a familiar way and already has support for ton of features.
I recently updated the notification feature in my personal application to this new approach. So if you want to dig deeper in more real scenario code, please access the pull request below.
Thanks a lot for Ian Lake for sharing his thoughts in Slack channel, as well as sharing some great demo for this scenario. ❤️