| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- //
- // LNDeeplinkManager.swift
- // Lanu
- //
- // Created by OneeChan on 2025/12/12.
- //
- import Foundation
- struct LNDeeplinkUrls {
- static let appScheme = "gami"
-
- enum web: String {
- case closeWindow
- case userCancellation
- case page
- case playmateApply
- }
-
- enum app: String {
- case profile
-
- enum qrcode: String {
- case order
- }
- }
-
- enum user: String {
- case category
- case profile
- }
- }
- extension RawRepresentable where RawValue == String {
- var deeplinkPath: String {
- let fullTypeName = String(reflecting: Self.self)
- let components = fullTypeName.components(separatedBy: CharacterSet(charactersIn: "<>[]()")).first!
-
- var nestedComponents = components.components(separatedBy: ".")
- if nestedComponents.count > 1 {
- // 移除最外层 lanu
- nestedComponents.removeFirst()
- }
- if nestedComponents.count > 1 {
- // 移除 LNDeeplinkUrls
- nestedComponents.removeFirst()
- }
- nestedComponents.append(rawValue)
- return nestedComponents.joined(separator: "/")
- }
- }
- class LNDeeplinkManager {
- static let shared = LNDeeplinkManager()
- typealias LNDeeplinkHandler<T: Decodable> = (T?) -> Void
-
- private let lock = NSLock()
- private var routerMap: [String: (Data?) -> Void] = [:]
-
- private init() {
- DispatchQueue.global().async { [weak self] in
- guard let self else { return }
- setupWebDeeplink()
- setupProfileDepplink()
- setupOrderDeeplink()
- }
- }
-
- func handleDeepLink(_ url: URL) {
- DispatchQueue.global().async { [weak self] in
- guard let self else { return }
-
- var fullPath = if url.scheme?.lowercased() == LNDeeplinkUrls.appScheme {
- if let host = url.host {
- "\(host)\(url.path)"
- } else {
- url.path
- }
- } else {
- url.path
- }
- if fullPath.hasPrefix("/") {
- fullPath = String(fullPath.dropFirst())
- }
-
- let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
- let params: [String: Any] = components?.queryItems?.reduce(into: [String: Any]())
- { partialResult, item in
- partialResult[item.name] = item.value
- } ?? [:]
-
- let jsonData = try? JSONSerialization.data(withJSONObject: params)
-
- lock.lock()
- let handler = routerMap[fullPath]
- lock.unlock()
-
- handler?(jsonData)
- }
- }
-
- func register<T: Decodable>(url: String, handler: @escaping LNDeeplinkHandler<T>) {
- lock.lock()
- routerMap[url] = { data in
- let model: T?
- if let data {
- let decoder = JSONDecoder()
- model = try? decoder.decode(T.self, from: data)
- } else {
- model = nil
- }
- runOnMain {
- handler(model)
- }
- }
- lock.unlock()
- }
-
- func register(url: String, handler: @escaping () -> Void) {
- lock.lock()
- routerMap[url] = { _ in
- runOnMain {
- handler()
- }
- }
- lock.unlock()
- }
- }
- extension LNDeeplinkManager {
- private func setupWebDeeplink() {
- register(url: LNDeeplinkUrls.web.page.deeplinkPath) { (param: LNWebPageDeeplinkParams?) in
- guard let param, !param.url.isEmpty else { return }
- UIView.appKeyWindow?.pushToWebView(param)
- }
- register(url: LNDeeplinkUrls.web.playmateApply.deeplinkPath) {
- UIView.appKeyWindow?.pushToJoinUs()
- }
- }
-
- private func setupProfileDepplink() {
- register(url: LNDeeplinkUrls.app.profile.deeplinkPath) { (param: LNProfileDeeplinkParams?) in
- guard let param, !param.uid.isEmpty else { return }
- UIView.appKeyWindow?.pushToProfile(uid: param.uid)
- }
- register(url: LNDeeplinkUrls.user.profile.deeplinkPath) { (param: LNProfileDeeplinkParams?) in
- guard let param, !param.id.isEmpty else { return }
- UIView.appKeyWindow?.pushToProfile(uid: param.id)
- }
- }
-
- private func setupOrderDeeplink() {
- register(url: LNDeeplinkUrls.app.qrcode.order.deeplinkPath) { (param: LNORCodeCreateOrderParams?) in
- guard let param, !param.qrcode.isEmpty else { return }
- LNOrderManager.shared.getQRDetail(data: param.qrcode) { res in
- guard let res else { return }
- UIView.appKeyWindow?.pushToCreateOrder(res)
- }
- }
- register(url: LNDeeplinkUrls.user.category.deeplinkPath) { (param: LNUserSkillParams?) in
- guard let param, !param.code.isEmpty else { return }
- LNOrderManager.shared.getQRDetail(data: param.code) { res in
- guard let res else { return }
- UIView.appKeyWindow?.pushToCreateOrder(res)
- }
- }
- }
- }
|