5

I am using the Navigation Component and I am trying to trigger an explicit deep linking to a specific destination, represented by a Fragment, when the user taps on a notification.

According to the documentation a pending intent can be create like this:

val bundle = bundleOf("id" to "1234")

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.myDestination)
    .setArguments(args)
    .createPendingIntent()

Where nav_graph is defined as follow:

<fragment 
   android:id="@+id/myDestination"
   android:name="MyFragment">

   <argument
      android:name="id"
      app:argType="string" />

   <deepLink app:uri="myApp://myFragment?id={id}" /> // Removing this line it works fine

</fragment>

I would then use the pendingIntent into the notification using the NotificationCompat.Builder with:

.setContentIntent(pendingIntent) 

When I tap on the notification the right destination is actually opened, but the value args.id would be "null" (not null, but a string with "null" value. In my fragment I have

private val args by navArgs<MyFragmentArgs>()

...

override fun onCreate(saveInstanceState: Bundle?) {
   args.id // The string value is "null". 
} 

However if I remove the <deepLink> from the fragment then it will work. The problem is that I need both implicit and explicit deep links. Is there a way for supporting both with Navigation Component?

GVillani82
  • 17,196
  • 30
  • 105
  • 172
  • For completeness, add the versions of each dependency you're using, in case someone investigates and finds a relevant bug in the Android code. Also, do you have a sample project that reproduces this? Something minimal that can be checked out and exercises this same problem? (aka: a two fragment project or similar). That's where I would start (given you haven't found a response in over two days). This is also what Google would "ask you" if you were to report a bug. The silly bot will say: "please provide an AStudio project..." – Martin Marconcini Jun 21 '21 at 08:09
  • In other words, unless someone knows *exactly* this situation, the only way to play around with this is to create a new project and start experimenting; setting all this up would take "hours", and nobody will likely do that in their spare time. – Martin Marconcini Jun 21 '21 at 08:12
  • `bundleOf("id", "1234")` is not a valid syntax for the [`bundleOf()` Kotlin extension](https://developer.android.com/reference/kotlin/androidx/core/os/package-summary#bundleof) - what `bundleOf` method are you using? Or does your code actually use the correct `bundleOf("id" to "1234")` syntax? – ianhanniballake Jun 22 '21 at 01:52
  • Ye, sorry, my code is indeed using the right syntax. I updated the question – GVillani82 Jun 22 '21 at 07:14

3 Answers3

1
val bundle = bundleOf("id" to "1234")

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.myDestination)
    .setArguments(args)
    .createPendingIntent()

What is your args variable, because you declare bundle above?

I have check and all code worked fine.

My nav_graph:

<fragment
        android:id="@+id/navigation_notifications"
        android:name="com.olopa.thefirst.ui.notifications.NotificationsFragment"
        android:label="@string/title_notifications"
        tools:layout="@layout/fragment_notifications">

        <deepLink app:uri="sampleapp://noti?id={id}" />

        <argument
            android:name="id"
            app:argType="string"
            app:nullable="true" />

When navigate by notification:

val bundle = bundleOf("id" to "12")

val pendingIntent = NavDeepLinkBuilder(this)
            .setGraph(R.navigation.mobile_navigation)
            .setDestination(R.id.navigation_notifications)
            .setArguments(bundle)
            .createPendingIntent()

And result: enter image description here

Or navigate by link:

navController.navigate(Uri.parse("sampleapp://noti?id=1"))

And result: enter image description here

dinhlam
  • 708
  • 3
  • 14
0

Try this way:

<fragment
    android:id="@+id/navigation_notifications"
    android:name="NotificationsFragment">

    <deepLink app:uri="sampleapp://app/noti?id={id}" /> // host and path is required

    <argument
        android:name="id"
        app:argType="string"
        app:nullable="true" />
</fragment>

register deeplinks in AndroidManifest.xml by (source)

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:label="@string/app_name">
    <nav-graph android:value="@navigation/mobile_navigation" />

    // other intent filters
</activity>

and create implicit pending intent:

val intent = Intent(Intent.ACTION_VIEW).apply {
    data = "sampleapp://app/noti?id=fromNotif".toUri()
    flags = Intent.FLAG_ACTIVITY_NEW_TASK
}

val pendingIntent = PendingIntent.getActivity(context, id, intent, flags)

val notification = NotificationCompat.Builder(context, channelName)
    // ...
    .setContentIntent(pendingIntent)
    .build()

So far it will launch the MainActivity.

If you're using <fragment> in its xml layout, it will automatically navigate on NotificationsFragment.

<fragment
    android:id="@+id/nav_host_fragment_activity_main"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:defaultNavHost="true"
    app:navGraph="@navigation/mobile_navigation" />

Otherwise handle it by your self:

if (intent.action == Intent.ACTION_VIEW && intent.data != null)
    navController.navigate(intent.data!!)
beigirad
  • 4,986
  • 2
  • 29
  • 52
-1

It might happen if your nav graph contains sum included graph inside. Opening with deep link intent data must have flat graph that your app can navigate through your fragment. One the other solution to your problem is using extra instead of data for example when you want to start your activity with intent that can active deeplink of fragment, you can use extra and action view. If you use NavDeepLinkBuilder this pass deeplink as data to your intent and when your activity open through pending intent it might have crash if your graph dont be flat and have included nav graph. See below code for better understanding the solution. First this is hard solution that have to exist flat nav graph

val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.data=Uri.parse("your deeplink url")

And you can use below code that is better and your nav graph can not change

val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra(INTENT_KEY,"your deeplink url")

and you can handle your intent data in your activity like this

intent?.getStringExtra(INTENT_KEY)?.let {
      navController.navigate(Uri.parse(it))
}

I prefer to use this because when you use NavDeepLinkBuilder you must to know your destination id and if you have a lot of usecase for navigating in app your problem just started to create a lot of if else. In this solution you can just pass your deep link as simple string

sajadab
  • 383
  • 2
  • 11