Files
suixinkan_uikit/suixinkan/Core/Push/PushModels.swift
T
lujiuyinandCursor 1b2637f0ee fix: 推送点击仅按 type 路由到收款页或消息中心。
对齐后端消息类型约定,去掉 route/uri 等兼容字段,并补充联调日志与单测。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-22 18:20:36 +08:00

87 lines
2.8 KiB
Swift

import Foundation
/// 推送点击后可到达的业务页面。
enum PushDestination: Sendable, Equatable {
case paymentRecord
case paymentDetails
case messageCenter
}
/// 极光/APNs payload 解析结果,仅提取业务消息类型用于点击路由。
struct PushPayload: Sendable, Equatable {
private let type: String
/// 从系统通知 userInfo 提取顶层或推送包装层中的业务消息类型。
nonisolated init(userInfo: [AnyHashable: Any]) {
type = Self.extractType(from: userInfo)
}
/// 从可发送的字符串字典创建 payload,仅保留业务消息类型。
nonisolated init(values: [String: String]) {
type = Self.normalizedType(values["type"])
}
/// 可发送的规范化字段快照。
nonisolated var normalizedValues: [String: String] {
type.isEmpty ? [:] : ["type": type]
}
/// 仅根据后端业务消息类型解析目标页面。
nonisolated var destination: PushDestination {
switch type {
case "1":
return .paymentRecord
case "6":
return .paymentDetails
default:
return .messageCenter
}
}
private nonisolated static func extractType(
from dictionary: [AnyHashable: Any],
depth: Int = 0
) -> String {
guard depth <= 4 else { return "" }
let directType = normalizedType(dictionary["type"])
guard directType.isEmpty else { return directType }
for key in nestedTypeContainerKeys {
guard let value = dictionary[key] else { continue }
if let nested = value as? [AnyHashable: Any] {
let nestedType = extractType(from: nested, depth: depth + 1)
if !nestedType.isEmpty { return nestedType }
continue
}
guard let text = value as? String,
let data = text.data(using: .utf8),
let object = try? JSONSerialization.jsonObject(with: data),
let nested = object as? [String: Any]
else { continue }
let bridged = Dictionary(uniqueKeysWithValues: nested.map {
(AnyHashable($0.key), $0.value)
})
let nestedType = extractType(from: bridged, depth: depth + 1)
if !nestedType.isEmpty { return nestedType }
}
return ""
}
private nonisolated static func normalizedType(_ value: Any?) -> String {
switch value {
case let string as String:
return string.trimmingCharacters(in: .whitespacesAndNewlines)
case let number as NSNumber:
return number.stringValue
default:
return ""
}
}
private nonisolated static let nestedTypeContainerKeys = [
"extras", "extra", "JMessageExtra", "n_extras",
]
}