From d5d5d97c2a0cd3b8e7d71977d17852454158ff07 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Fri, 13 Mar 2026 11:34:10 +0900 Subject: [PATCH] =?UTF-8?q?fix(notification):=20=ED=91=B8=EC=8B=9C=20?= =?UTF-8?q?=EB=94=A5=EB=A7=81=ED=81=AC=20=EC=9A=B0=EC=84=A0=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=20=EB=B6=84=EA=B8=B0=EB=A5=BC=20=EB=B3=B4=EC=A0=95?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SodaLive/Sources/App/AppDeepLinkHandler.swift | 1 + SodaLive/Sources/App/AppDelegate.swift | 9 ++++++ SodaLive/Sources/App/AppState.swift | 1 + SodaLive/Sources/Main/Home/HomeView.swift | 7 ++++- docs/20260313_푸시터치딥링크실행분기수정.md | 28 +++++++++++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 docs/20260313_푸시터치딥링크실행분기수정.md diff --git a/SodaLive/Sources/App/AppDeepLinkHandler.swift b/SodaLive/Sources/App/AppDeepLinkHandler.swift index c721d42..263f3de 100644 --- a/SodaLive/Sources/App/AppDeepLinkHandler.swift +++ b/SodaLive/Sources/App/AppDeepLinkHandler.swift @@ -44,6 +44,7 @@ enum AppDeepLinkHandler { switch action { case .live(let roomId): guard roomId > 0 else { return } + AppState.shared.isPushRoomFromDeepLink = true AppState.shared.pushRoomId = 0 AppState.shared.pushRoomId = roomId diff --git a/SodaLive/Sources/App/AppDelegate.swift b/SodaLive/Sources/App/AppDelegate.swift index 11874fd..095f5eb 100644 --- a/SodaLive/Sources/App/AppDelegate.swift +++ b/SodaLive/Sources/App/AppDelegate.swift @@ -265,6 +265,15 @@ extension AppDelegate : UNUserNotificationCenterDelegate { // With swizzling disabled you must let Messaging know about the message, for Analytics Messaging.messaging().appDidReceiveMessage(userInfo) Notifly.userNotificationCenter(center, didReceive: response) + + let deepLinkString = (userInfo["deep_link"] as? String ?? "") + .trimmingCharacters(in: .whitespacesAndNewlines) + + if !deepLinkString.isEmpty { + _ = AppDeepLinkHandler.handle(urlString: deepLinkString) + completionHandler() + return + } let roomIdString = userInfo["room_id"] as? String let contentIdString = userInfo["content_id"] as? String diff --git a/SodaLive/Sources/App/AppState.swift b/SodaLive/Sources/App/AppState.swift index a1671ba..fd790bf 100644 --- a/SodaLive/Sources/App/AppState.swift +++ b/SodaLive/Sources/App/AppState.swift @@ -50,6 +50,7 @@ class AppState: ObservableObject { @Published var pushAudioContentId = 0 @Published var pushSeriesId = 0 @Published var pendingDeepLinkAction: AppDeepLinkAction? = nil + @Published var isPushRoomFromDeepLink = false @Published var roomId = 0 { didSet { if roomId <= 0 { diff --git a/SodaLive/Sources/Main/Home/HomeView.swift b/SodaLive/Sources/Main/Home/HomeView.swift index 9f0cf9d..f424424 100644 --- a/SodaLive/Sources/Main/Home/HomeView.swift +++ b/SodaLive/Sources/Main/Home/HomeView.swift @@ -319,17 +319,22 @@ struct HomeView: View { } let roomId = value + let isPushRoomFromDeepLink = appState.isPushRoomFromDeepLink appState.pushRoomId = 0 + appState.isPushRoomFromDeepLink = false DispatchQueue.main.async { handleExternalNavigationRequest( value: roomId, navigationAction: { - appState.setAppStep(step: .main) + if !isPushRoomFromDeepLink { + appState.setAppStep(step: .main) + } liveViewModel.enterLiveRoom(roomId: roomId) }, cancelAction: { appState.pushRoomId = 0 + appState.isPushRoomFromDeepLink = false } ) } diff --git a/docs/20260313_푸시터치딥링크실행분기수정.md b/docs/20260313_푸시터치딥링크실행분기수정.md new file mode 100644 index 0000000..757ec8a --- /dev/null +++ b/docs/20260313_푸시터치딥링크실행분기수정.md @@ -0,0 +1,28 @@ +# 20260313 푸시 터치 딥링크 실행 분기 수정 + +## 작업 목표 +- 푸시 메시지 터치 시 `deep_link` 파라미터가 비어 있지 않으면 딥링크를 우선 실행하고, 비어 있으면 기존 푸시 이동 로직을 유지한다. +- 앱 실행 상태에 따라 딥링크 실행 시점을 분리한다. + - 실행 중: 메인 페이지 재호출 없이 현재 페이지에서 목적지로 이동 + - 미실행(콜드 스타트): `HomeView` 표시 이후 딥링크 실행 + +## 구현 체크리스트 +- [x] 푸시 터치 payload에서 `deep_link` 파라미터 파싱 및 우선 실행 분기 추가 +- [x] `deep_link` 미존재/빈 값일 때 기존 `push*` 기반 이동 로직 유지 +- [x] 앱 실행 상태별(실행 중/미실행) 딥링크 실행 타이밍 보정 +- [x] 진단/빌드/테스트 검증 및 결과 기록 + +## 검증 기록 +- 무엇/왜/어떻게: `UNUserNotificationCenterDelegate`의 푸시 탭 진입점(`AppDelegate.userNotificationCenter(_:didReceive:withCompletionHandler:)`)에서 `deep_link`가 비어 있지 않으면 `AppDeepLinkHandler.handle(urlString:)`를 우선 실행하고 즉시 종료하도록 분기했다. `deep_link`가 비어 있을 때만 기존 `room_id/content_id/channel_id/message_id` 파싱 로직을 유지해 기존 이동 흐름을 보존했다. +- 무엇/왜/어떻게: 앱 실행 중 딥링크 라이브 이동에서 기존 `.main` 재호출을 막기 위해 `AppState.isPushRoomFromDeepLink` 플래그를 추가하고, `AppDeepLinkHandler`의 `.live` 액션에서 플래그를 세운 뒤 `HomeView`의 `pushRoomId` 처리에서 플래그가 `true`일 때 `.main` 호출 없이 바로 `liveViewModel.enterLiveRoom(roomId:)`를 수행하도록 수정했다. +- 무엇/왜/어떻게: 앱 미실행(콜드 스타트) 시 딥링크 실행 타이밍은 기존 `AppDeepLinkHandler.handle`의 `pendingDeepLinkAction` 큐잉과 `SplashView.nextAppStep()`의 `setAppStep(.main)` 이후 지연 실행 구조를 그대로 사용해 `HomeView` 표시 이후 딥링크가 실행되도록 유지했다. +- 실행 명령: `lsp_diagnostics` (`SodaLive/Sources/App/AppDelegate.swift`, `SodaLive/Sources/App/AppState.swift`, `SodaLive/Sources/App/AppDeepLinkHandler.swift`, `SodaLive/Sources/Main/Home/HomeView.swift`) +- 결과: 로컬 SourceKit 단독 컨텍스트에서 `No such module 'UIKit'`, `No such module 'Firebase'` 및 연쇄 참조 미해결이 발생했다. 코드 유효성은 아래 빌드 명령으로 재검증했다. +- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build` +- 결과: `** BUILD SUCCEEDED **` +- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` +- 결과: `** BUILD SUCCEEDED **` +- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test` +- 결과: `Scheme SodaLive is not currently configured for the test action.` +- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test` +- 결과: `Scheme SodaLive-dev is not currently configured for the test action.`