feat: add setPlayMode SDK API with isActivated precondition
This commit is contained in:
@@ -291,6 +291,56 @@ public final class DuooomiBleSDK: NSObject {
|
||||
})
|
||||
}
|
||||
|
||||
/// 切换播放模式(0=单播 / 1=循环播放)。
|
||||
///
|
||||
/// 复用 `BIND_DEVICE` (0x0F) 命令通道;响应类型为 `BindingResponse`。
|
||||
/// 成功后自动刷新一次 `deviceInfo`(含最新 `loop` 字段),与 expo 端行为对齐。
|
||||
///
|
||||
/// - Important: 此方法要求 **设备已和该 `userId` 完成 `bind`**(即 `isActivated == true`)。
|
||||
/// 未绑定状态下设备会返回 `success=0`;SDK 在客户端先做守卫,直接返回失败而不发命令。
|
||||
/// - Note: `bind` / `unbind` / `setPlayMode` 共享 `0x0F` / `0x12` opId 通道,**不能并发**。
|
||||
public func setPlayMode(
|
||||
_ mode: PlayMode,
|
||||
userId: String,
|
||||
completion: @escaping (Result<BindingResponse, Error>) -> Void
|
||||
) {
|
||||
guard ensureConnected(completion: completion) else { return }
|
||||
guard isActivated else {
|
||||
BleLog.w("setPlayMode called before bind (isActivated=false)", "Command")
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(DuooomiBleError.bindingFailed("Device not bound; call bind(userId:) first")))
|
||||
}
|
||||
return
|
||||
}
|
||||
BleLog.d("Sending setPlayMode (mode=\(mode), userId=\(userId))", "Command")
|
||||
|
||||
sendAndWait(commandType: .bindDevice, completion: { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
case .success(let data):
|
||||
do {
|
||||
let resp = try self.decodeResponse(BindingResponse.self, from: data)
|
||||
if resp.success != 1 {
|
||||
BleLog.w("setPlayMode failed: device rejected", "Command")
|
||||
completion(.failure(DuooomiBleError.bindingFailed("Set play mode failed")))
|
||||
return
|
||||
}
|
||||
BleLog.i("setPlayMode success: mode=\(mode)", "Command")
|
||||
// 自动刷新 deviceInfo(含最新 loop 字段)
|
||||
self.getDeviceInfo { _ in
|
||||
completion(.success(resp))
|
||||
}
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}, send: {
|
||||
try self.deviceInfoService.setPlayMode(userId: userId, loop: mode)
|
||||
})
|
||||
}
|
||||
|
||||
/// 解除设备绑定
|
||||
public func unbind(userId: String, completion: @escaping (Result<UnbindResponse, Error>) -> Void) {
|
||||
guard ensureConnected(completion: completion) else { return }
|
||||
|
||||
@@ -81,3 +81,25 @@ final class BindPayloadEncodingTests: XCTestCase {
|
||||
XCTAssertEqual(dict["loop"] as? Int, 0)
|
||||
}
|
||||
}
|
||||
|
||||
final class SetPlayModeGuardTests: XCTestCase {
|
||||
private func makeSDK() -> DuooomiBleSDK {
|
||||
DuooomiBleSDK(config: DuooomiBleConfig(apiKey: "test"))
|
||||
}
|
||||
|
||||
func testSetPlayModeFailsWhenNotConnected() {
|
||||
let sdk = makeSDK()
|
||||
let exp = expectation(description: "completion")
|
||||
sdk.setPlayMode(.loop, userId: "u1") { result in
|
||||
switch result {
|
||||
case .success:
|
||||
XCTFail("expected failure when not connected")
|
||||
case .failure(let error):
|
||||
XCTAssertTrue("\(error)".lowercased().contains("connect"),
|
||||
"expected notConnected-style error, got \(error)")
|
||||
}
|
||||
exp.fulfill()
|
||||
}
|
||||
wait(for: [exp], timeout: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user