feat(sdk): 绑定时上报设备 log 到 update-metadata 并内聚双层绑定

- bind(userId:) 内聚为硬绑 + getVersion + 软绑 + updateMetadata 一次原子调用,
  软绑失败自动硬解绑回滚 + 清状态;集成方无需感知双层绑定
- fetchLatestFirmware 简化为对账上报 + checkUpgrade 两步,不再重复软绑
- VersionInfo 增加 log: [String: Any]?,走 JSONSerialization 解析(放弃 Codable);
  SDK 暴露只读 versionLog,断连/解绑/软绑回滚时清空
- ShipmentSnDeviceService 新增 updateMetadata(sn:data:),抽出 performPOST
  共享 HTTP 编排,新增 postAnyJSON 支持 [String: Any] body
- 老固件不返回 log → versionLog == nil → 自动跳过 updateMetadata,前向兼容

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
km2023
2026-05-18 16:25:55 +08:00
parent cdcf36a75b
commit 4bc8fdb64d
6 changed files with 163 additions and 67 deletions

View File

@@ -7,17 +7,17 @@ import Foundation
extension DuooomiBleSDK {
/// ****
/// ****
///
/// 1. **** pending `UpgradeRecord`
/// 2. ****POST `/api/auth/loomart/shipment-sn/device/bind`
/// - BLE 0x12 + `isActivated`/`sn` fetch
/// 3. **** `self.firmwareUpgrade` completion
/// 2. **** `self.firmwareUpgrade` completion
///
/// / metadata / `bind(userId:)`
///
/// - Parameters:
/// - sn: bind `sdk.sn`
/// - currentVersion: `sdk.version`
/// - userId: ID
/// - userId: ID failureReason
public func fetchLatestFirmware(
sn: String,
currentVersion: String,
@@ -34,41 +34,18 @@ extension DuooomiBleSDK {
// Step 1: OTA sn in-flight
self.tryReportPendingUpgrade(sn: sn, currentVersion: currentVersion, userId: userId)
// Step 2: shipment-sn HTTP
// BLE 0x12 + isActivated/sn
// fetchLatestFirmware bind
BleLog.d("Soft bind start: sn=\(sn)", "Firmware")
shipmentService.bind(sn: sn, bindUserId: userId) { [weak self] result in
// Step 2: checkUpgrade
self.firmwareUpgradeService.checkUpgrade(sn: sn, currentVersion: currentVersion) { [weak self] result in
guard let self = self else { return }
if case .failure(let err) = result {
BleLog.e("Soft bind failed during fetchLatestFirmware: \(err.localizedDescription); rolling back hard unbind", "Firmware")
// fire-and-forgetBLE ack fetch
self.deviceInfoService.unbindDevice(userId: userId) { rollbackResult in
if case .failure(let rbErr) = rollbackResult {
BleLog.w("Hard unbind rollback failed (ignored): \(rbErr.localizedDescription)", "Firmware")
} else {
BleLog.i("Hard unbind rollback sent", "Firmware")
}
switch result {
case .success(let r):
DispatchQueue.main.async {
self.firmwareUpgrade = r
completion(.success(r))
}
self.isActivated = false
self.sn = ""
case .failure(let err):
BleLog.w("checkUpgrade failed: \(err.localizedDescription)", "Firmware")
DispatchQueue.main.async { completion(.failure(err)) }
return
}
BleLog.i("Soft bind success: sn=\(sn)", "Firmware")
// Step 3: checkUpgrade
self.firmwareUpgradeService.checkUpgrade(sn: sn, currentVersion: currentVersion) { result in
switch result {
case .success(let r):
DispatchQueue.main.async {
self.firmwareUpgrade = r
completion(.success(r))
}
case .failure(let err):
BleLog.w("checkUpgrade failed: \(err.localizedDescription)", "Firmware")
DispatchQueue.main.async { completion(.failure(err)) }
}
}
}
}