I'm facing an issue with deep links in my Android app. When a user receives a push notification with a deep link, it works perfectly if the app is already running, but when the app is completely closed (not in recent apps), clicking the notification opens the app but ignores the deep link entirely.
Using Firebase Cloud Messaging for push notifications Navigation with Jetpack Compose Navigation Using custom URI scheme:appNAme://chat/{chatId}/{userId}
The Problem
When app is running or in background: Deep link navigation works perfectly When app is completely closed: App opens, but deep link is ignored (no logs indicate the deep link was processed)
my curent Code
Firebase Messaging Service (AppFirebaseMessagingService.kt) kotlin
override fun onMessageReceived(remoteMessage: RemoteMessage) { // Message processing... var title = "" var message = "" var category = "chat" var deepLink: String? = null var notificationId = System.currentTimeMillis().toInt()
if (remoteMessage.data.isNotEmpty()) { title = remoteMessage.data["title"] ?: "" message = remoteMessage.data["message"] ?: "" category = remoteMessage.data["category"] ?: category deepLink = remoteMessage.data["deepLink"] // ... } // Show notification if we have content if (title.isNotEmpty() || message.isNotEmpty()) { showNotification(notificationId, title, message, category, deepLink) }}
private fun showNotification( notificationId: Int, title: String, message: String, category: String, deepLink: String? ) { val intent = if (!deepLink.isNullOrEmpty()) { Intent(Intent.ACTION_VIEW, deepLink.toUri()).apply {
package= packageName addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) } } else { Intent(this, MainActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } }Log.d("FCMService", "Creating notification with intent: $intent") Log.d("FCMService", "Intent URI: ${intent.data}") val pendingIntent = PendingIntent.getActivity( this, System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT ) // Build notification val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(title) .setContentText(message) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_HIGH) val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(notificationId, notificationBuilder.build())} 2. MainActivity Deep Link Handling kotlinoverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
// Setup UI, etc... setContent { navController = rememberNavController() AppAndroidTheme { // Main content... } } if (intent?.action == Intent.ACTION_VIEW) { handleDeepLink(intent) }}
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) logIntent("onNewIntent", intent)
// Set the new intent setIntent(intent) navController.handleDeepLink(intent) // Handle it if it's a deep link if (intent.action == Intent.ACTION_VIEW) { handleDeepLink(intent) }}
private fun handleDeepLink(intent: Intent) { val uri = intent.data Log.d(TAG, "Processing deep link URI: $uri")
if (uri != null && uri.scheme == "appNAme") { when (uri.host) { "chat" -> { // Extract path segments val pathSegments = uri.pathSegments Log.d(TAG, "Path segments: $pathSegments") if (pathSegments.size >= 2) { val chatId = pathSegments[0] val userId = pathSegments[1] Log.d(TAG, "Navigating to chat: chatId=$chatId, userId=$userId") // Wait for UI to be ready before navigating Handler(Looper.getMainLooper()).postDelayed({ navigateToChat(chatId, userId) }, 300) } } } }}
private fun navigateToChat(chatId: String, userId: String) { try { Log.d(TAG, "Attempting navigation to chat screen with chatId=$chatId, userId=$userId") navController.navigate(MainScreens.ChatScreen(chatId, userId)) { popUpTo(navController.graph.findStartDestination().id) { saveState = true } launchSingleTop = true restoreState = true } Log.d(TAG, "Navigation completed") } catch (e: Exception) { Log.e(TAG, "Navigation error", e) } }NavGraph Deep Link Configuration kotlin
composable<MainScreens.ChatScreen>( deepLinks = listOf( navDeepLink<MainScreens.ChatScreen>( basePath = "$uri//chat" ){ uriPattern = "appANme://chat/{chatId}/{selectedProviderId}"} ) ) { val chatRoute: MainScreens.ChatScreen = it.toRoute() ChatScreen( chatId = chatRoute.chatId, selectedUserId = chatRoute.selectedProviderId, onNavigateBack = { navController.popBackStack() } ) }
AndroidManifest.xml
<!-- Deep link intent filter --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="chat" android:pathPattern="/.*" android:scheme="appname" /> </intent-filter>
What I've Tried
Using a trampoline/helper activity to handle deep links Different intent flags (FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TASK) Using LaunchedEffect to process deep links after NavController initialization Different launchMode settings in AndroidManifest Using a broadcast receiver to handle deep links Using TaskStackBuilder to create proper back stack Different timing delays for processing the deep link
Debug Logs When the app is already running, I see proper logs:
FCMService: Message received: notification=com.google.firebase.messaging.RemoteMessage$Notification@6bbba6f, data={messageId=1454719f-82ff-42d9-856c-27b64e57921d, chatId=wKu3Y4NHzPDSmBQG9sOt, messageType=TEXT, category=chat, timestamp=1743720987827, title=Pixel 9 sent you a message, click_action=android.intent.action.VIEW, deepLink=appNAme://chat/wKu3Y4NHzPDSmBQG9sOt/bxlAM2GCMCcwHLjHSL0cNqmef4r1, message=fed up menhh, senderId=bxlAM2GCMCcwHLjHSL0cNqmef4r1}
DeepLinkDebug: onNewIntent called with intent: Intent { act=android.intent.action.VIEW dat=appNAme://chat/... flg=0x14000000 pkg=com.talos.appNAme cmp=com.talos.appNAme/.ui.MainActivity }
DeepLinkDebug: Intent action: android.intent.action.VIEW
DeepLinkDebug: Intent data: appNAme://chat/wKu3Y4NHzPDSmBQG9sOt/bxlAM2GCMCcwHLjHSL0cNqmef4r1
DeepLinkDebug: Processing deep link URI: appNAme://chat/wKu3Y4NHzPDSmBQG9sOt/bxlAM2GCMCcwHLjHSL0cNqmef4r1
DeepLinkDebug: Path segments: [wKu3Y4NHzPDSmBQG9sOt, bxlAM2GCMCcwHLjHSL0cNqmef4r1]
DeepLinkDebug: Navigating to chat: chatId=wKu3Y4NHzPDSmBQG9sOt, userId=bxlAM2GCMCcwHLjHSL0cNqmef4r1
DeepLinkDebug: Attempting navigation to chat screen with chatId=wKu3Y4NHzPDSmBQG9sOt, userId=bxlAM2GCMCcwHLjHSL0cNqmef4r1
DeepLinkDebug: Navigation completed
But when the app is completely closed, I see NO logs at all when clicking the notification, only the standard app launch logs when it opens:
DeepLinkDebug: MainActivity onCreate with intent: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10600000 pkg=com.talos.appNAme cmp=com.talos.appNAme/.ui.MainActivity bnds=[440,2416][671,2676] }
DeepLinkDebug: Intent action: android.intent.action.MAIN
DeepLinkDebug: Intent data: null
DeepLinkDebug: Intent extras: null
my question How can I get deep links to work properly when the app is launched from a completely closed state via a push notification? It seems the deep link intent gets lost or is not being passed properly when the app is cold started. I'd appreciate any insights or solutions to this problem!
-
Did you find a solution? Because I have the same problem.Mohammed Imam– Mohammed Imam2025年10月15日 19:10:21 +00:00Commented Oct 15 at 19:10
1 Answer 1
you can find answer here firebase.google.com/docs/cloud-messaging/...
Try to put title and message into notification object instead of data object
{
"message":{
"token":"..",
"notification":{
"title":"title",
"body":"here your message"
},
"data" : {
"custom_arg_1" : "custom_arg_1",
"custom_arg_2" : "custom_arg_2"
}
}
}
Comments
Explore related questions
See similar questions with these tags.