Home > Mobile >  Handle FCM notifications with navigation component
Handle FCM notifications with navigation component

Time:03-08

I'm developing an Android app with navigation component, I added the deeplink to the navigation

<fragment
    android:id="@ id/searchFragment"
    android:label="@string/navigation_search_label"
    tools:layout="@layout/fragment_search">
    <deepLink
        android:id="@ id/deepLink2"
        app:uri="http://example/search" />
</fragment>

And added the navigation file to AndroidManifest :

        <nav-graph android:value="@navigation/nav_graph" />

But I can't find how to send the uri in FCM and how to handle it so that the user can be redirected to that fragment. Anyone have experience on this?

CodePudding user response:

You don't need to set uri in FCM, just send required data in fcm message and construct uri in your application.

Here's what you need to send from backend (remember to send data)

val data = mapOf("someId" to "12345")

val notification = Notification.builder()
    .setTitle(title)
    .setBody(body)
    .build()

val message = Message.builder()
    .setToken(token)
    .setNotification(notification)
    .putAllData(data)
    .build()

firebaseMessaging.send(message)

Then, use below code in your (android) messaging service to receive (and construct) notification in both foregroud/backgruoud app scenario

class YourFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        remoteMessage.notification?.let {
            val intent = Intent(this, MainActivity::class.java).apply {
                remoteMessage.data.forEach { (k, v) ->
                    putExtra(k, v)
                }
            }

            // Create PendingIntent with backstack maintained
            val pendingIntent = TaskStackBuilder.create(this).run {
                addNextIntentWithParentStack(intent)
                getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
            }

            val builder = NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
                    .setSmallIcon(R.drawable.your_logo)
                    .setContentTitle(it.title)
                    .setContentText(it.body)
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                    .setContentIntent(pendingIntent)
                    .setDefaults(Notification.DEFAULT_SOUND)
                    .setAutoCancel(true)

            with(NotificationManagerCompat.from(this)) {
                notify(remoteMessage.messageId?.toIntOrNull() ?: 1, builder.build())
            }
        }
    }
}

And finally, in your MainActivity

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // other stuff...

        intent.extras?.let {
            // Construct url (or multiple url based on requirement)
            val url = "$YOUR_WEBSITE_NAME/user/${intent.getStringExtra("someId")}"
            val intent = Intent(
                Intent.ACTION_VIEW,
                url.toUri(),
                this,
                MainActivity::class.java
            )
            startActivity(intent)
        }
    }
}

CodePudding user response:

One has to set a click_action for the notification... else there won't be any URL Intent.
In Android Studio run configurations one can select "Launch Options" > "Launch" > "URL".
This effectively simulates clicking such a link - which is quite useful for testing deep-links.

An IntentFilter needs to be registered in the AndroidManifest.xml, to filter the URL Intent:

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <data android:scheme="https"/>
    <data android:host="acme.com"/>
</intent-filter>

<nav-graph
    android:value="@navigation/nav_graph"/>

Also make sure to have the corresponding .well-known/assetlinks.json hosted on that domain.

Use deepLink and argument for navigation:

<deepLink
    app:uri="https://acme.com/search?term={searchTerm}"/>

<argument
    android:name="searchTerm"
    app:argType="string"/>
  • Related