230 lines
7.1 KiB
Swift
230 lines
7.1 KiB
Swift
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<AnyCancellable>()
|
|
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() }
|
|
}
|
|
}
|