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:
@@ -4,24 +4,44 @@ public struct VersionInfo: Equatable {
|
||||
public let version: String
|
||||
/// 命令类型标识,设备可能返回 Int (如 7) 或 String (如 "0x07")
|
||||
public let type: String
|
||||
}
|
||||
/// 设备运行日志,BLE 响应中 `log` 字段对应的任意 JSON 对象;缺失/非对象时为 nil。
|
||||
/// SDK 不解析其内部结构,原样透传给 `update-metadata` 接口。
|
||||
public let log: [String: Any]?
|
||||
|
||||
extension VersionInfo: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case version, type
|
||||
public init(version: String, type: String, log: [String: Any]? = nil) {
|
||||
self.version = version
|
||||
self.type = type
|
||||
self.log = log
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
version = try container.decode(String.self, forKey: .version)
|
||||
public static func == (lhs: VersionInfo, rhs: VersionInfo) -> Bool {
|
||||
guard lhs.version == rhs.version, lhs.type == rhs.type else { return false }
|
||||
return NSDictionary(dictionary: lhs.log ?? [:]).isEqual(to: rhs.log ?? [:])
|
||||
}
|
||||
}
|
||||
|
||||
// type may come as Int or String from different firmware versions
|
||||
if let str = try? container.decode(String.self, forKey: .type) {
|
||||
type = str
|
||||
} else if let num = try? container.decode(Int.self, forKey: .type) {
|
||||
type = "\(num)"
|
||||
extension VersionInfo {
|
||||
/// 从设备 BLE 响应字节流(已剥离 0 字节)解析。
|
||||
/// type 字段兼容 Int / String 两种返回形态;log 字段缺失/非对象时返回 nil。
|
||||
static func parse(from data: Data) throws -> VersionInfo {
|
||||
let cleaned = data.filter { $0 != 0 }
|
||||
let object = try JSONSerialization.jsonObject(with: cleaned)
|
||||
guard let json = object as? [String: Any] else {
|
||||
throw DuooomiBleError.transferFailed("VersionInfo: top-level not an object")
|
||||
}
|
||||
|
||||
let version = (json["version"] as? String) ?? ""
|
||||
|
||||
let type: String
|
||||
if let s = json["type"] as? String {
|
||||
type = s
|
||||
} else if let n = json["type"] as? NSNumber {
|
||||
type = "\(n.intValue)"
|
||||
} else {
|
||||
type = ""
|
||||
}
|
||||
|
||||
let log = json["log"] as? [String: Any]
|
||||
return VersionInfo(version: version, type: type, log: log)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user