Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deeplinking to another module with parameters

I'm trying to navigate using a deep-link for cross-module user navigation, and I need to pass some parameters. Since it's in another module, I don't have access to the id, so all of the navigate(@IdRes int resId, ...) methods are off the table.

What's the best way to navigate a deep link with a Uri and a Bundle of key-value-pairs using Android Jetpack's Navigation component?

navigation.xml (:app module)

<?xml version="1.0" encoding="utf-8"?>
<navigation 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/navGraph"
    app:startDestination="@id/feature_one">

    <include app:graph="@navigation/feature_one" />
    <include app:graph="@navigation/feature_two />
</navigation>

feature_one.xml (:one module)

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/feature_one"
    app:startDestination="@id/oneFragment">
    <fragment
        android:id="@+id/oneFragment"
        android:name="my.app.OneFragment"
        android:label="OneFragment" />
</navigation>

feature_two.xml (:two module)

<?xml version="1.0" encoding="utf-8"?>
<navigation 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/feature_two"
    app:startDestination="@id/twoFragment">

    <fragment
        android:id="@+id/twoFragment"
        android:name="my.app.TwoFragment"
        android:label="TwoFragment">
        <deepLink app:uri="myapp://my.app/?myId={myId}" />

        <argument android:name="myId" app:argType="long" />

    </fragment>
</navigation>

OneFragment.kt (:one module)

    val bundle = bundleOf("myId" to 123L)

    val request = NavDeepLinkRequest.Builder
         .fromUri("myapp://my.app?myId={myId}")
         .build()

    // No place to bundle the args

    findNavController().navigate(
        request,
        navOptions
    )

TwoFragment.kt (:two module)

    private val args: TwoFragmentArgs by navArgs()

    ...
    
        val myId: Long = args.myId // never set, so how?
like image 435
tyler Avatar asked Apr 30 '26 15:04

tyler


1 Answers

tldr: double check make sure you are encoding everything correctly while creating the request, especially if you are using parameters with more than one word, whitespaces or special character, you will need to use the Uri.Builder methods that already encode things for you or encode them yourself beforehand

Your xmls are defined correctly, the problem is how you are building the URI.

I was doing almost the same as you but using

    val myId = 123L
    val uri =  Uri.Builder().path("myapp://my.app/$myId")
        .build()
    val request = NavDeepLinkRequest.Builder
        .fromUri(uri)
        .build()
    findNavController().navigate(request)

And the deep link couldn't match this URI and it gives this Exception java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{...

I was able to solve it by changing the way the URI was built

Building it like this

val myId = 123L
val uri =  Uri.Builder().scheme("myapp")
    .authority("my.app")
    .path("/$myId")
    .build()
val request = NavDeepLinkRequest.Builder
    .fromUri(uri)
    .build()
findNavController().navigate(request)

or like this (as in @SUR4IDE answer)

val myId = 123L
val correctyEncodedId = URLEncoder.encode(myId, "utf-8")
val request = NavDeepLinkRequest.Builder
   .fromUri(Uri.parse("myapp://my.app/$correctyEncodedId"))
   .build()
    findNavController().navigate(request)

Both approaches avoid a problem where the path String was being encoded somewhat different, especially if the argument has whitespaces or special characters that are differently encoded in a URI, and was not matching the deep link defined within feature_two.xml in my scenario. The URI string was being encoded as "myapp%3A//my.app/123" and this : encoding difference was making the match not work and so it was like I wasn't using the defined deep link.

When the match works, the Navigation classes will match the arguments from your URI to the ones defined in the .xml (they have to be named exactly the same, as you did) and will create a Bundle with them as args and pass it to the Fragment or Activity it will navigate to.

like image 179
cesonha Avatar answered May 02 '26 05:05

cesonha