Отправить аргумент через PendingIntent NavDeepLinkBuilder

У меня возникли трудности с отправкой аргумента через PendingIntent уведомления с использованием NavDeepLinkBuilder, Я могу получить пункт назначения Activity запустить, нажав на уведомление, но Activity"s Intent не содержит значение аргумента, которое я передал через NavDeepLinkBuilder, Intent вместо этого возвращает defaultValue что я установил в графе навигации - "noJobId".

Создание уведомления:

val notification =
    NotificationCompat.Builder(context, context.getString(R.string.notification_channel_id_new_job))
        .setSmallIcon(R.drawable.icon_launcher)
        .setStyle(NotificationCompat.DecoratedCustomViewStyle())
        .setCustomContentView(contentView)
        .setPriority(NotificationCompat.PRIORITY_MAX)
        .setOngoing(true)
        .setSound(getAlertSoundUri(context))
        .setVibrate(vibrationPattern)
        .setContentIntent(
            NavDeepLinkBuilder(context)
                .setComponentName(NewJobDetailsActivity::class.java)
                .setGraph(R.navigation.main_graph)
                .setDestination(R.id.newJobDetailsActivity)
                .setArguments(
                    NewJobDetailsActivityArgs.Builder()
                        .setJobId(event.jobId)
                        .build()
                        .toBundle()
                )
                .createPendingIntent()
        )
        .setDeleteIntent(
            PendingIntent.getBroadcast(
                context,
                0,
                Intent(context, NewJobNotificationRemovalReceiver::class.java).apply {
                    action = NewJobNotificationRemovalReceiver.ACTION_CLEARED
                    putExtra(NewJobNotificationRemovalReceiver.EXTRA_JOB_ID, event.jobId)
                },
                0
            )
        )
        .build()
notification.flags = Notification.FLAG_ONLY_ALERT_ONCE and Notification.FLAG_INSISTENT
notificationManager.notify(notificationId, notification)

context используется в уведомлении FirebaseMessagingService,

Место назначения ActivityonCreate():

val jobId: String = NewJobDetailsActivityArgs.fromBundle(intent?.extras).jobId

main_graph.xmlНавигационный график:

<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_graph"
    app:startDestination="@id/jobsFragment">

    <fragment
        android:id="@+id/jobsFragment"
        android:name=".ui.jobs.JobsFragment"
        android:label="JobsFragment">

        <action
            android:id="@+id/action_jobsFragment_to_newJobDetailsActivity"
            app:destination="@id/newJobDetailsActivity" />

    </fragment>

    <fragment
        android:id="@+id/historyFragment"
        android:name=".ui.history.HistoryFragment"
        android:label="HistoryFragment" />

    <fragment
        android:id="@+id/profileFragment"
        android:name=".ui.profile.ProfileFragment"
        android:label="ProfileFragment" />

    <activity
        android:id="@+id/newJobDetailsActivity"
        android:name=".ui.job.NewJobDetailsActivity"
        android:label="activity_new_job_details"
        tools:layout="@layout/activity_new_job_details">

        <argument
            android:name="jobId"
            android:defaultValue="noJobId" // just for testing
            app:argType="string" />

    </activity>

</navigation>

Кто-нибудь еще сталкивался с этой проблемой? Я чувствую, что это ошибка в компоненте навигации, но я еще не уверен на 100%. Любопытно, есть ли что-то, что я здесь упускаю.

Зависимости: android.arch.navigation: navigation-фрагмент-ktx:1.0.0-alpha06, android.arch.navigation:navigation-ui-ktx:1.0.0-alpha06

Плагин: androidx.navigation.safeargs

3 ответа

Я разместил эту проблему на общедоступном трекере Google и получил следующий ответ:

NavDeepLinkBuilder передает свои аргументы в NavController для глубокой связи в конкретное место назначения. Направления деятельности - это действительно больше точек выхода из графика навигации, чем то, с чем можно / должно быть тесно связано.

Источник: https://issuetracker.google.com/issues/118964253

Автор этой цитаты рекомендует использовать TaskStackBuilder вместо NavDeepLinkBuilder при создании PendingIntent чей пункт назначения Activity, Вот то, что я закончил с:

NotificationCompat.Builder(context, context.getString(R.string.notification_channel_id_new_job))
    ...
    .setContentIntent(
        TaskStackBuilder.create(context).run {
            addNextIntentWithParentStack(Intent(context, DestinationActivity::class.java).apply {
                putExtras(DestinationActivityArgs.Builder(jobId).build().toBundle())
            })
            getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
        }
    )
    .build()

Это решение позволяет мне успешно глубокую ссылку на пункт назначения Activity все еще будучи в состоянии ссылаться на аргументы, определенные в графике навигации для этого Activity через сгенерированный DestinationActivityArgs строитель и доступ к аргументам из пункта назначения Activity"s onCreate() метод работает.

Это решение также правильно обрабатывает случаи, когда задача приложения отсутствует в списке "недавних приложений", приложение на переднем плане показывает некоторые другие Activity или же Fragmentили приложение находится на переднем плане и уже находится в пункте назначения Activity, addNextIntentWithParentStack() правильно обрабатывает навигацию, поэтому нажимая кнопку вверх от пункта назначения Activity возвращается к логическому родителю Activity как определено в AndroidManifest,

Немного огорчает, что это решение не использует библиотеку Navigation Architecture для создания PendingIntent, но это похоже на лучшую альтернативу.

Вы можете найти все аргументы, которые вы отправляете в arguments переменная вашего Activity/Fragment.

Вот пример того, как получить Stringаргумент установлен в PendingIntent, созданный NavDeepLinkBuilder() с ключомEVENT_KEY в месте назначения Activity/Fragment:

requireArguments().getString(YourClass.EVENT_KEY)?.let { it } ?: ""

Обратите внимание, что наш getString() вызов может вернуть значение null, если искомого значения нет, поэтому убедитесь, что Bundle вы в конечном итоге назначаете NavDeepLinkBulder().setArguments() заполняется так, как вы этого хотите!

У меня была такая же проблема, мой пакет всегда возвращал null, это то, что у меня сработало:

  1. В моем фрагменте у меня есть метод, который передает пакет:

            notificationManager.sendNotification(
        requireArguments(), // This gets me the arguments supplied when the fragment in instantiated
        requireContext()
    )
    
  2. В моем уведомленииUtils мое намерение контента:

            fun NotificationManager.sendNotification(
        bundle: Bundle,
        appContext: Context
    ) {
        val contentIntent = NavDeepLinkBuilder(appContext)
            .setComponentName(MainActivity::class.java)
            .setGraph(R.navigation.navigation)
            .setDestination(R.id.detailsFragment)
            .setArguments(bundle)
            .createPendingIntent()
    
            // Rest of code to build the notification... 
    }
    
  3. Чтобы проверить правильность передачи пакета, я зарегистрировал следующее:

            Timber.d("The name is: ${bundle.getParcelable<Person>("Person")?.name}")