feat(gift): 선물 상세 딥링크를 연결한다

This commit is contained in:
Yu Sung
2026-10-08 12:33:14 +09:00
parent 8d3d7f6ba1
commit b526dae7e1
3 changed files with 110 additions and 0 deletions
@@ -5,6 +5,7 @@ enum AppDeepLinkAction {
case userCreatorChat(roomId: Int)
case content(contentId: Int)
case series(seriesId: Int)
case giftDetail(applicationNo: String)
case community(creatorId: Int, postId: Int?)
case message
case audition
@@ -70,6 +71,9 @@ enum AppDeepLinkHandler {
guard seriesId > 0 else { return }
AppState.shared.setAppStep(step: .seriesDetail(seriesId: seriesId))
case .giftDetail(let applicationNo):
AppState.shared.setAppStep(step: .giftDetail(applicationNo: applicationNo))
case .community(let creatorId, let postId):
guard creatorId > 0 else { return }
@@ -148,6 +152,13 @@ enum AppDeepLinkHandler {
return .series(seriesId: value)
}
if let value = queryMap["deeplinkvalue"]?.trimmingCharacters(in: .whitespacesAndNewlines),
value.caseInsensitiveCompare("GIFT_DETAIL") == .orderedSame,
let applicationNo = queryMap["deeplinkid"]?.trimmingCharacters(in: .whitespacesAndNewlines),
!applicationNo.isEmpty {
return .giftDetail(applicationNo: applicationNo)
}
if let communityId = queryMap["community_id"], let value = Int(communityId), value > 0 {
return .community(creatorId: value, postId: communityPostId(queryMap: queryMap))
}
@@ -0,0 +1,88 @@
import Foundation
enum AppStep: Equatable {
case splash
case main
case userCreatorChatRoom(roomId: Int)
case contentDetail(contentId: Int)
case seriesDetail(seriesId: Int)
case creatorCommunityAll(creatorId: Int)
case message
case audition
case giftDetail(applicationNo: String)
}
enum UserDefaultsKey { case userId }
enum UserDefaults {
static func int(forKey: UserDefaultsKey) -> Int { 0 }
}
final class AppState {
static let shared = AppState()
var rootStep: AppStep = .main
var pendingDeepLinkAction: AppDeepLinkAction?
var appliedStep: AppStep?
var isPushRoomFromDeepLink = false
var pushRoomId = 0
func setAppStep(step: AppStep) { appliedStep = step }
func setPendingCommunityCommentDeepLink(creatorId: Int, postId: Int) {}
func clearPendingCommunityCommentDeepLink() {}
}
let APPSCHEME = "soda"
@main
enum GiftDetailDeepLinkCheck {
static var assertions = 0
static func check(_ condition: @autoclosure () -> Bool, _ message: String) {
assertions += 1
guard condition() else { fatalError("FAIL: \(message)") }
}
static func settle() {
RunLoop.current.run(until: Date().addingTimeInterval(0.05))
}
static func main() {
let valid = "voiceon://?DeepLinkValue=gift_detail&DEEPLINKID=GIFT-2026-%30%30%31"
check(AppDeepLinkHandler.handle(urlString: valid), "valid gift detail accepted")
settle()
check(AppState.shared.appliedStep == .giftDetail(applicationNo: "GIFT-2026-001"), "decoded identifier routes to gift detail")
AppState.shared.appliedStep = nil
check(AppDeepLinkHandler.handle(urlString: "voiceon://?deepLinkValue=%20GIFT_DETAIL%20&deepLinkId=%20GIFT-2026-002%20"), "trimmed semantic values accepted")
settle()
check(AppState.shared.appliedStep == .giftDetail(applicationNo: "GIFT-2026-002"), "identifier whitespace trimmed")
for url in [
"voiceon://?deepLinkValue=GIFT_DETAIL",
"voiceon://?deepLinkId=GIFT-2026-003",
"voiceon://?deepLinkValue=GIFT_DETAIL&deepLinkId=%20%20",
"voiceon://?deepLinkValue=OTHER&deepLinkId=GIFT-2026-004",
"http://?deepLinkValue=GIFT_DETAIL&deepLinkId=GIFT-2026-005"
] {
check(!AppDeepLinkHandler.handle(urlString: url), "rejects invalid or unsupported \(url)")
}
AppState.shared.rootStep = .splash
AppState.shared.pendingDeepLinkAction = nil
AppState.shared.appliedStep = nil
check(AppDeepLinkHandler.handle(urlString: "voiceon://?deepLinkValue=GIFT_DETAIL&deepLinkId=GIFT-2026-006"), "valid splash link accepted")
settle()
if case .giftDetail(let applicationNo)? = AppState.shared.pendingDeepLinkAction {
check(applicationNo == "GIFT-2026-006", "splash stores gift action")
} else {
check(false, "splash stores gift action")
}
check(AppState.shared.appliedStep == nil, "splash does not apply gift action")
AppState.shared.rootStep = .main
AppState.shared.appliedStep = nil
AppState.shared.pendingDeepLinkAction = nil
check(AppDeepLinkHandler.handle(urlString: "voiceon://?content_id=42&deepLinkValue=GIFT_DETAIL&deepLinkId=GIFT-2026-007"), "existing content route accepted")
settle()
check(AppState.shared.appliedStep == .contentDetail(contentId: 42), "existing content route still applies")
print("PASS AppDeepLinkGiftDetailCheck assertions=\(assertions)")
}
}
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail
root="$(cd "$(dirname "$0")/../.." && pwd)"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
swiftc "$root/SodaLive/Sources/App/AppDeepLinkHandler.swift" \
"$root/work/tests/AppDeepLinkGiftDetailCheck.swift" \
-o "$tmp/check"
"$tmp/check"