import UIKit import Combine import DuooomiBleSDK struct DiscoveredDevice: Identifiable { let id: String let name: String let rssi: Int } struct DeviceInfo { let brand: String let screenSize: String let freeSpace: Int let totalSpace: Int let batteryLevel: Int } struct LogEntry: Identifiable { let id = UUID() let time: Date let message: String } @MainActor class SDKManager: ObservableObject { static let shared = SDKManager() // State @Published var btState = "idle" @Published var connectedDevice: [String: Any]? = nil @Published var deviceInfo: DeviceInfo? = nil @Published var version = "" @Published var isActivated = false @Published var transferProgress: Int = 0 @Published var error: String? = nil @Published var discoveredDevices: [DiscoveredDevice] = [] @Published var logs: [LogEntry] = [] @Published var isSDKReady = false private var cancellables = Set() private var listenerIds: [String] = [] private init() {} func initialize() { ReactNativeHostManager.shared.initialize() // 加载 RN 视图启动 JS 运行时 do { let view = try ReactNativeHostManager.shared.loadView( moduleName: "main", initialProps: nil, launchOptions: nil) // 保持引用防止释放 _rnView = view log("SDK initialized, RN runtime started") isSDKReady = true } catch { log("SDK init failed: \(error.localizedDescription)") } setupSubscriptions() setupMessageListener() } private var _rnView: UIView? // MARK: - State Subscriptions private func setupSubscriptions() { BrownfieldState.subscribe("btState") { [weak self] value in DispatchQueue.main.async { let state = value as? String ?? "idle" self?.btState = state self?.log("btState → \(state)") } }.store(in: &cancellables) BrownfieldState.subscribe("connectedDevice") { [weak self] value in DispatchQueue.main.async { self?.connectedDevice = value as? [String: Any] if let device = value as? [String: Any] { self?.log("connectedDevice → \(device["name"] ?? "unknown")") } else { self?.log("connectedDevice → nil") } } }.store(in: &cancellables) BrownfieldState.subscribe("deviceInfo") { [weak self] value in DispatchQueue.main.async { if let dict = value as? [String: Any] { self?.deviceInfo = DeviceInfo( brand: dict["brand"] as? String ?? "", screenSize: dict["screenSize"] as? String ?? "", freeSpace: dict["freeSpace"] as? Int ?? 0, totalSpace: dict["totalSpace"] as? Int ?? 0, batteryLevel: dict["batteryLevel"] as? Int ?? 0 ) self?.log("deviceInfo updated") } else { self?.deviceInfo = nil } } }.store(in: &cancellables) BrownfieldState.subscribe("version") { [weak self] value in DispatchQueue.main.async { self?.version = value as? String ?? "" if let v = value as? String { self?.log("version → \(v)") } } }.store(in: &cancellables) BrownfieldState.subscribe("isActivated") { [weak self] value in DispatchQueue.main.async { self?.isActivated = value as? Bool ?? false } }.store(in: &cancellables) BrownfieldState.subscribe("transferProgress") { [weak self] value in DispatchQueue.main.async { self?.transferProgress = value as? Int ?? 0 } }.store(in: &cancellables) BrownfieldState.subscribe("error") { [weak self] value in DispatchQueue.main.async { self?.error = value as? String if let e = value as? String { self?.log("ERROR: \(e)") } } }.store(in: &cancellables) BrownfieldState.subscribe("discoveredDevices") { [weak self] value in DispatchQueue.main.async { if let arr = value as? [[String: Any]] { self?.discoveredDevices = arr.compactMap { dict in guard let id = dict["id"] as? String else { return nil } return DiscoveredDevice( id: id, name: dict["name"] as? String ?? "Unknown", rssi: dict["rssi"] as? Int ?? 0 ) } } else { self?.discoveredDevices = [] } } }.store(in: &cancellables) } // MARK: - Message Listener private func setupMessageListener() { let id = BrownfieldMessaging.addListener { [weak self] message in DispatchQueue.main.async { let event = message["event"] as? String ?? "unknown" self?.log("Event: \(event) — \(message)") } } listenerIds.append(id) } // MARK: - Actions func scan() { log("→ scan") BrownfieldMessaging.sendMessage(["action": "scan"]) } func stopScan() { log("→ stopScan") BrownfieldMessaging.sendMessage(["action": "stopScan"]) } func connect(deviceId: String) { log("→ connect \(deviceId)") BrownfieldMessaging.sendMessage(["action": "connect", "deviceId": deviceId]) } func disconnect() { log("→ disconnect") BrownfieldMessaging.sendMessage(["action": "disconnect"]) } func bind(userId: String) { log("→ bind \(userId)") BrownfieldMessaging.sendMessage(["action": "bind", "userId": userId]) } func unbind(userId: String) { log("→ unbind \(userId)") BrownfieldMessaging.sendMessage(["action": "unbind", "userId": userId]) } func getDeviceInfo() { log("→ getDeviceInfo") BrownfieldMessaging.sendMessage(["action": "getDeviceInfo"]) } func getVersion() { log("→ getVersion") BrownfieldMessaging.sendMessage(["action": "getVersion"]) } func deleteFile(key: String) { log("→ deleteFile \(key)") BrownfieldMessaging.sendMessage(["action": "deleteFile", "key": key]) } func transferFile(fileUri: String, commandType: Int) { log("→ transferFile \(fileUri)") BrownfieldMessaging.sendMessage([ "action": "transferFile", "fileUri": fileUri, "commandType": commandType ]) } // MARK: - Logging private func log(_ message: String) { let entry = LogEntry(time: Date(), message: message) logs.insert(entry, at: 0) if logs.count > 200 { logs.removeLast() } } }