Files
frontend-app/uni_modules/tb-douyin-pay/utssdk/app-ios/TbDouyinPayNative.swift
T

99 lines
4.0 KiB
Swift

import Foundation
import UIKit
import DypaySDK
public class TbDouyinPayNative {
private static var pending: ((String) -> Void)?
private static var generation = UUID()
public static func initialize(_ appId: String, _ scheme: String, _ link: String) {
DypayAPI.register(withAppID: appId, universalLink: link, callbackScheme: scheme)
}
public static func available() -> Bool { DypayAPI.canOpenDypay() }
public static func resetPending() {
DispatchQueue.main.async {
generation = UUID()
pending = nil
}
}
public static func pay(_ payload: String, _ done: @escaping (String) -> Void) {
DispatchQueue.main.async {
guard pending == nil else {
done("{\"resultCode\":\"103\",\"errorMsg\":\"已有支付正在处理,请先查单\"}")
return
}
guard DypayAPI.canOpenDypay() else {
done("{\"resultCode\":\"100\",\"errorMsg\":\"请安装或升级抖音客户端\"}")
return
}
guard let bytes = payload.data(using: .utf8),
let info = try? JSONSerialization.jsonObject(with: bytes) as? [String: String],
let controller = foregroundController() else {
done("{\"resultCode\":\"2\",\"errorMsg\":\"支付参数或当前页面不可用\"}")
return
}
generation = UUID()
let ticket = generation
pending = done
DypayAPI.openDypay(withInfo: info, from: controller) { result in
finish(result as? [AnyHashable: Any], ticket)
}
// Only authenticated server reconciliation can release a missing callback's lock.
// URL callbacks are hints, never payment success; the host always queries its saved order.
}
}
public static func processURL(_ url: URL) -> Bool {
let ticket = generation
return DypayAPI.processDypayResult(with: url) { result in
finish(result as? [AnyHashable: Any], ticket)
}
}
public static func processActivity(_ activity: NSUserActivity) -> Bool {
let ticket = generation
return DypayAPI.processDypayResult(with: activity) { result in
finish(result as? [AnyHashable: Any], ticket)
}
}
private static func finish(_ result: [AnyHashable: Any]?, _ ticket: UUID) {
DispatchQueue.main.async {
guard ticket == generation, let callback = pending else { return }
pending = nil
let code = result?["resultCode"].map { String(describing: $0) } ?? "3"
let message = result?["errorMsg"] as? String ?? ""
let normalized = ["resultCode": code, "errorMsg": message]
guard let data = try? JSONSerialization.data(withJSONObject: normalized),
let json = String(data: data, encoding: .utf8) else {
callback("{\"resultCode\":\"3\",\"errorMsg\":\"请查询订单状态\"}")
return
}
callback(json)
}
}
private static func foregroundController() -> UIViewController? {
var windows: [UIWindow] = []
if #available(iOS 13.0, *) {
windows = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.filter { $0.activationState == .foregroundActive }
.flatMap { $0.windows }
} else {
windows = UIApplication.shared.windows
}
var controller = windows.first(where: { $0.isKeyWindow })?.rootViewController
while let current = controller {
if let presented = current.presentedViewController { controller = presented }
else if let nav = current as? UINavigationController { controller = nav.visibleViewController }
else if let tabs = current as? UITabBarController { controller = tabs.selectedViewController }
else { break }
}
return controller
}
}