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:
@@ -38,10 +38,54 @@ final class ShipmentSnDeviceService {
|
||||
)
|
||||
}
|
||||
|
||||
/// 上报设备运行 metadata。`data` 是任意 JSON 对象(典型场景:BLE getVersion 返回的 log 字段),
|
||||
/// SDK 不做 schema 校验,原样透传。2xx 即视为成功。
|
||||
func updateMetadata(
|
||||
sn: String,
|
||||
data: [String: Any],
|
||||
completion: @escaping (Result<Void, Error>) -> Void
|
||||
) {
|
||||
postAnyJSON(
|
||||
path: "/api/auth/loomart/shipment-sn/device/update-metadata",
|
||||
body: ["sn": sn, "data": data],
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
private func post(
|
||||
path: String,
|
||||
body: [String: String],
|
||||
completion: @escaping (Result<Void, Error>) -> Void
|
||||
) {
|
||||
let bodyData: Data
|
||||
do {
|
||||
bodyData = try JSONEncoder().encode(body)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
performPOST(path: path, bodyData: bodyData, completion: completion)
|
||||
}
|
||||
|
||||
private func postAnyJSON(
|
||||
path: String,
|
||||
body: [String: Any],
|
||||
completion: @escaping (Result<Void, Error>) -> Void
|
||||
) {
|
||||
let bodyData: Data
|
||||
do {
|
||||
bodyData = try JSONSerialization.data(withJSONObject: body, options: [])
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
performPOST(path: path, bodyData: bodyData, completion: completion)
|
||||
}
|
||||
|
||||
private func performPOST(
|
||||
path: String,
|
||||
bodyData: Data,
|
||||
completion: @escaping (Result<Void, Error>) -> Void
|
||||
) {
|
||||
guard let url = URL(string: config.apiHost.absoluteString + path) else {
|
||||
completion(.failure(DuooomiBleError.softBindFailed("URL 拼装失败")))
|
||||
@@ -55,13 +99,7 @@ final class ShipmentSnDeviceService {
|
||||
req.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||
req.setValue(config.apiKey, forHTTPHeaderField: "x-api-key")
|
||||
req.setValue(config.brand, forHTTPHeaderField: "x-owner")
|
||||
|
||||
do {
|
||||
req.httpBody = try JSONEncoder().encode(body)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
req.httpBody = bodyData
|
||||
|
||||
session.dataTask(with: req) { data, resp, error in
|
||||
if let error = error {
|
||||
|
||||
Reference in New Issue
Block a user