import Foundation import UIKit import XuqmCoreSDK /// JSBridge 标准处理器 /// 提供 xuqm.* 命名空间的标准桥接方法 public final class XWebViewStandardHandlers { private weak var viewController: UIViewController? private var onClose: (() -> Void)? public init(viewController: UIViewController? = nil, onClose: (() -> Void)? = nil) { self.viewController = viewController self.onClose = onClose } /// 处理 JS 消息 /// - Returns: 是否已处理 public func handleMessage(_ message: [String: Any]) -> Bool { guard let action = message["action"] as? String else { return false } let callbackId = message["callbackId"] as? String switch action { case "xuqm.getDeviceInfo": handleGetDeviceInfo(callbackId: callbackId) return true case "xuqm.getToken": handleGetToken(callbackId: callbackId) return true case "xuqm.getUserInfo": handleGetUserInfo(callbackId: callbackId) return true case "xuqm.closeWebView": handleCloseWebView() return true case "xuqm.showToast": handleShowToast(message: message) return true default: return false } } // MARK: - Handlers private func handleGetDeviceInfo(callbackId: String?) { guard let callbackId = callbackId else { return } let device = UIDevice.current let model = device.model let osVersion = "iOS \(device.systemVersion)" let platform = "IOS" let deviceId = device.identifierForVendor?.uuidString ?? "" callCallback(callbackId, data: [ "model": model, "osVersion": osVersion, "platform": platform, "deviceId": deviceId, ]) } private func handleGetToken(callbackId: String?) { guard let callbackId = callbackId else { return } let token = XuqmSDK.shared.token ?? "" callCallback(callbackId, data: ["token": token]) } private func handleGetUserInfo(callbackId: String?) { guard let callbackId = callbackId else { return } let userId = XuqmSDK.shared.currentUserId ?? "" callCallback(callbackId, data: ["userId": userId]) } private func handleCloseWebView() { onClose?() } private func handleShowToast(message: [String: Any]) { guard let msg = message["message"] as? String else { return } DispatchQueue.main.async { [weak self] in guard let vc = self?.viewController else { return } let alert = UIAlertController(title: nil, message: msg, preferredStyle: .alert) vc.present(alert, animated: true) DispatchQueue.main.asyncAfter(deadline: .now() + 2) { alert.dismiss(animated: true) } } } // MARK: - Callback private func callCallback(_ callbackId: String, data: [String: Any]) { guard let jsonData = try? JSONSerialization.data(withJSONObject: data), let jsonString = String(data: jsonData, encoding: .utf8) else { return } let js = "window[\"\(callbackId)\"](\(jsonString))" // The WebView will execute this JS through its controller NotificationCenter.default.post( name: .xWebViewCallJs, object: nil, userInfo: ["js": js] ) } /// 生成注入的 JS 代码 public static var injectedJavaScript: String { return """ (function() { window.xuqm = window.xuqm || {}; window.xuqm.getDeviceInfo = function(callback) { var callbackId = 'cb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); window[callbackId] = function(data) { if (callback) callback(data); delete window[callbackId]; }; window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'xuqm.getDeviceInfo', callbackId: callbackId })); }; window.xuqm.getToken = function(callback) { var callbackId = 'cb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); window[callbackId] = function(data) { if (callback) callback(data.token); delete window[callbackId]; }; window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'xuqm.getToken', callbackId: callbackId })); }; window.xuqm.getUserInfo = function(callback) { var callbackId = 'cb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); window[callbackId] = function(data) { if (callback) callback(data); delete window[callbackId]; }; window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'xuqm.getUserInfo', callbackId: callbackId })); }; window.xuqm.closeWebView = function() { window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'xuqm.closeWebView' })); }; window.xuqm.showToast = function(message) { window.ReactNativeWebView.postMessage(JSON.stringify({ action: 'xuqm.showToast', message: message })); }; })(); true; """ } } // MARK: - Notification Name extension Notification.Name { static let xWebViewCallJs = Notification.Name("xWebViewCallJs") }