From 9c642fb3b7f48be60d160ccd36a5caad129ff5b4 Mon Sep 17 00:00:00 2001 From: klaus Date: Fri, 19 Jun 2026 05:03:14 +0900 Subject: [PATCH] =?UTF-8?q?fix(dm):=20FCM=20deep=5Flink=20payload=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=83=9D=EC=84=B1=EC=9D=84=20=EB=B3=B4?= =?UTF-8?q?=EC=A0=95=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fcm/SodaFirebaseMessagingService.kt | 9 +++++-- .../SodaFirebaseMessagingServiceSourceTest.kt | 24 +++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt b/app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt index d0b1e56e..25ceb22a 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt @@ -31,6 +31,8 @@ class SodaFirebaseMessagingService : FirebaseMessagingService() { remoteMessage.notification != null ) { sendNotification(remoteMessage.data, remoteMessage.notification) + } else if (hasDeepLink(remoteMessage.data)) { + sendNotification(remoteMessage.data, remoteMessage.notification) } else if (remoteMessage.data["message"]?.isNotBlank() == true) { sendNotification(remoteMessage.data, remoteMessage.notification) } @@ -43,6 +45,11 @@ class SodaFirebaseMessagingService : FirebaseMessagingService() { SharedPreferenceManager.pushToken = token } + private fun hasDeepLink(messageData: Map): Boolean { + return messageData["deepLink"]?.isNotBlank() == true || + messageData["deep_link"]?.isNotBlank() == true + } + private fun sendNotification( messageData: Map, notification: RemoteMessage.Notification? @@ -78,13 +85,11 @@ class SodaFirebaseMessagingService : FirebaseMessagingService() { val deepLinkExtras = if (!deepLinkUrl.isNullOrBlank()) { android.os.Bundle().apply { putString("deep_link", deepLinkUrl) - messageData["chat_type"]?.let { putString("chat_type", it) } messageData["room_id"]?.let { putString("room_id", it) } } } else { android.os.Bundle().apply { messageData["room_id"]?.let { putString("room_id", it) } - messageData["chat_type"]?.let { putString("chat_type", it) } messageData["message_id"]?.let { putString("message_id", it) } messageData["content_id"]?.let { putString("content_id", it) } messageData["channel_id"]?.let { putString("channel_id", it) } diff --git a/app/src/test/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingServiceSourceTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingServiceSourceTest.kt index b6cf95fb..f07e9726 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingServiceSourceTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingServiceSourceTest.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.fcm +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import java.io.File @@ -7,19 +8,19 @@ import java.io.File class SodaFirebaseMessagingServiceSourceTest { @Test - fun `FCM notification extras는 DM chat_type과 기존 deep link 값을 보존한다`() { + fun `FCM notification extras는 기존 deep link 값을 보존하고 chat_type을 사용하지 않는다`() { val source = projectFile( "app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt" ).readText() - assertTrue(source.contains("messageData[\"chat_type\"]?.let { putString(\"chat_type\", it) }")) + assertFalse(source.contains("chat_type")) assertTrue(source.contains("messageData[\"room_id\"]?.let { putString(\"room_id\", it) }")) assertTrue(source.contains("messageData[\"message_id\"]?.let { putString(\"message_id\", it) }")) assertTrue(source.contains("messageData[\"deep_link_value\"]?.let { putString(\"deep_link_value\", it) }")) } @Test - fun `FCM deepLink payload도 DM chat_type과 room_id를 extra bundle에 보존한다`() { + fun `FCM deepLink payload는 deep_link와 room_id를 extra bundle에 보존한다`() { val source = projectFile( "app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt" ).readText() @@ -29,10 +30,25 @@ class SodaFirebaseMessagingServiceSourceTest { val deepLinkBundleSource = source.substring(deepLinkBundleStart, fallbackBundleStart) assertTrue(deepLinkBundleSource.contains("putString(\"deep_link\", deepLinkUrl)")) - assertTrue(deepLinkBundleSource.contains("messageData[\"chat_type\"]?.let { putString(\"chat_type\", it) }")) assertTrue(deepLinkBundleSource.contains("messageData[\"room_id\"]?.let { putString(\"room_id\", it) }")) } + @Test + fun `FCM deep_link 단독 payload는 deep_link extra와 ACTION_VIEW data로 보존한다`() { + val source = projectFile( + "app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt" + ).readText() + + assertTrue(source.contains("} else if (hasDeepLink(remoteMessage.data)) {")) + assertTrue(source.contains("private fun hasDeepLink(messageData: Map): Boolean")) + assertTrue(source.contains("messageData[\"deepLink\"]?.isNotBlank() == true")) + assertTrue(source.contains("messageData[\"deep_link\"]?.isNotBlank() == true")) + assertTrue(source.contains("val deepLinkUrl = messageData[\"deepLink\"] ?: messageData[\"deep_link\"]")) + assertTrue(source.contains("intent.action = Intent.ACTION_VIEW")) + assertTrue(source.contains("intent.data = Uri.parse(deepLinkUrl)")) + assertTrue(source.contains("putString(\"deep_link\", deepLinkUrl)")) + } + private fun projectFile(relativePath: String): File { val candidates = listOf(File(relativePath), File("../$relativePath")) return candidates.firstOrNull { it.exists() }