跳到主要内容

Android 数据与设备能力

SDK Version: 1.0.0
Package: com.xtalk.mesh.sdk.ble

除图片转码外,本页业务接口都要求 ensureInitialized() 成功;发送类接口还要求连接、认证和初始化完成。阻塞/等待设备结果的方法在 Dispatchers.IO 调用。返回值枚举的具体成员以交付核心 SDK 的 IDE 补全为准;只有明确的成功成员才算成功,不要把“非空”当作成功。

1. 二进制与 RF

API选择时机结果语义
sendBinaryFrame(data)普通二进制业务帧SendResult;空包/长度/状态/连接错误由枚举反映
sendRfPayloadAndWaitSendFinish(rawPayload, timeoutMs)需要设备完成确认true 表示在期限内收到发送完成;超时/错误为 false
sendRfPayloadNoWait(rawPayload)实时语音/低延迟控制帧只报告是否受理,不等发送完成;空包为 false
val ok = withContext(Dispatchers.IO) {
XTalkBleClient.sendRfPayloadAndWaitSendFinish(frame, timeoutMs = 3_000L)
}

普通可靠业务优先 waited 版本;只有能自行节流、容忍丢包的实时流才使用 no-wait。不要与 Auth、Init 或自定义 AT 并发。

2. 原始 AT 与透传所有权(Advanced)

API契约
runAtCommand(...)独占无线锁、返回响应行;详见 API 参考
sendAtCommand(command)返回 SendResult,不提供响应行
sendAtCommandNoWait(command)只报告写入受理
sendEncryptedAt(bytes)输入是已按交付协议编码的 AT 字节;成功为 true
setPassthroughListener(listener)设置底层透传唯一 listener,null 释放;会影响 runAtCommand,只允许 transport 作者短期使用
withWirelessOpLock(block)让高级客户操作与 Auth/Init/AT 串行;不得从已持锁路径再次等待自身
val lines = withContext(Dispatchers.IO) {
XTalkBleClient.runAtCommand(
command = "AT+RATE?",
timeoutMs = 1_500L,
errorPolicy = BleAtErrorPolicy.FAIL_FAST,
)
}

BleAtErrorPolicy.COLLECT_UNTIL_COMPLETE 只和明确的 stopWhen 一起使用。drainResponseTailAfterStop = truestopWhen 必填,SDK 会在载荷匹配后继续持有 listener/锁到终止行或原截止时间。

3. 文本与数据接收

private val textListener = TextReceivedCallback { sourceId, text, snr, rssi ->
// 切换到主线程更新 UI。
}
private val dataListener = DataReceivedCallback { bytes, length, snr, rssi ->
val payload = bytes.copyOf(length.coerceIn(0, bytes.size))
}

XTalkBleClient.addTextListener(textListener)
XTalkBleClient.addDataListener(dataListener)
val result = XTalkBleClient.sendText("hello")

// 生命周期结束
XTalkBleClient.removeTextListener(textListener)
XTalkBleClient.removeDataListener(dataListener)
  • sendText(text) 返回 SendResult;空文本、长度限制和状态错误按枚举处理。
  • DataReceivedCallback 在高频 I/O 路径触发,不要阻塞;数据只使用 0 until length
  • TextReceivedCallback 提供源 ID、文本、SNR、RSSI。

4. 文件发送与接收

private val sendListener = FileSendCallback { progress, sent, total, result ->
// progress/bytes/result 共同判断完成或失败。
}
private val receiveListener = FileReceiveCallback { progress, received, total, result, bytes ->
if (bytes != null) savePrivately(bytes)
}

XTalkBleClient.addFileSendListener(sendListener)
XTalkBleClient.addFileReceiveListener(receiveListener)
val accepted = XTalkBleClient.sendFile(fileBytes)

// 用户取消
XTalkBleClient.cancelFileSend()
XTalkBleClient.cancelFileReceive()

// 页面销毁
XTalkBleClient.removeFileSendListener(sendListener)
XTalkBleClient.removeFileReceiveListener(receiveListener)

sendFile/cancel 返回 SendResult 只表示请求状态;最终进度与结果看对应 callback。客户决定文件选择、大小预检、存储路径和隐私授权。一次只运行一个占用无线通道的文件/AT/Auth/Init 操作。完成或取消后可调用 restoreTextPttDefaults() 恢复文本/PTT 参数。

5. PTT 与实时语音

需要运行时 RECORD_AUDIO 权限。

API参数/默认生命周期
startPttVoiceCapture(enablePcmCallback = true)是否回调本地 PCMstopPttVoiceCapture() 配对
startRealtimeVoiceCapture(peopleCount = 2, mute = 0)人数和静音标志stopRealtimeVoiceCapture() 配对
stopVoiceCaptureLocal()只结束本地采集,用于异常/快速清理
setRealtimeWorkModeOverride(workMode)null 清除会话前设置,会话后清除
getRealtimeWorkModeOverride()返回当前 override 或 null
private val received = VoiceReceivedCallback { sourceId, pcm, length, snr, rssi, isLast ->
consumeRemotePcm(pcm.copyOf(length.coerceIn(0, pcm.size)), isLast)
}
private val captured = VoiceCaptureCallback { pcm, length, isLast ->
consumeLocalPcm(pcm.copyOf(length.coerceIn(0, pcm.size)), isLast)
}

XTalkBleClient.addVoiceListener(received)
XTalkBleClient.addVoiceCaptureListener(captured)
val started = XTalkBleClient.startPttVoiceCapture(enablePcmCallback = true)
// ...
XTalkBleClient.stopPttVoiceCapture()
XTalkBleClient.removeVoiceCaptureListener(captured)
XTalkBleClient.removeVoiceListener(received)

语音帧是实时路径,callback 内不要做文件 I/O、网络请求或 UI 阻塞。只在成功 start 后调用相应 stop;断线时允许调用本地 stop 做幂等清理。

6. PCM 播放

val started = XTalkBleClient.startVoicePlayback(pcmBytes)
// 用户停止或播放结束后的业务清理:
val stopped = XTalkBleClient.stopVoicePlayback()

输入必须是交付协议要求的 PCM 格式。PlaybackStartResult/PlaybackStopResult 明确表示是否启动/停止;不要依据耗时推断成功。

7. 图片转码

val output: ImageTranscodeResult = XTalkBleClient.transcodeImage(
imageBytes = encodedImage,
targetTier = ImageTargetTier.SMALL, // 以交付枚举实际成员为准
inputFormat = null, // null 表示自动识别
)

transcodeImage(imageBytes, targetTier, inputFormat = null) 是离线 CPU 操作,不要求 BLE、Auth、Init 或录音权限;大图仍应在后台线程处理。结果对象包含交付核心 SDK 定义的状态和输出,先检查其成功状态再使用输出字节。

8. 16 字节加密密钥

require(key.size == 16)
check(XTalkBleClient.setCryptoKey16(key))
key.fill(0) // 业务不再需要明文时清除客户侧副本

setCryptoKey16 必须传恰好 16 字节;返回 false 时禁止继续加密业务。不要写日志、Analytics 或持久化明文密钥。

9. 无线设置

API差别
setChannelFrequency(freqHz, timeoutMs = 3000)通过无线配置 callback 等待 channel 设置成功
setFrequencyHz(freqHz, timeoutMs = 3000)通过 AT 同时设置四路频率
setRateMode(rateMode)把值限制到 0..255 后发送;设备是否支持仍由返回值决定
restoreTextPttDefaults(rate = 7, addtl = 1, work = 21)依次恢复三项;全部成功才返回 true

频率只能使用客户项目和部署地区获准值。设置失败后停止发送并查询实际值;不要无限重试。

10. 硬件、固件、电量与管理回调

private val manage = DeviceManageCallback { type, value ->
// 异步管理事件;按 type 安全转换 value。
}
XTalkBleClient.addDeviceManageListener(manage)

val hw = withContext(Dispatchers.IO) { XTalkBleClient.getHardwareVersion(2_000L) }
val fw = withContext(Dispatchers.IO) { XTalkBleClient.getFirmwareVersion(2_000L) }
val battery = withContext(Dispatchers.IO) { XTalkBleClient.getBatteryLevel(4_000L) }

XTalkBleClient.removeDeviceManageListener(manage)

三项查询成功后会缓存;失败/超时/不支持返回 null。电量是设备报告的整数,不应在文档层假设额外范围或单位。断开会清空缓存。

11. 监听器总表

添加移除回调用途/线程
addListenerremoveListener扫描/连接状态;主线程分发
addDataListenerremoveDataListener二进制/实时数据;I/O 回调线程
addDeviceManageListenerremoveDeviceManageListener版本、电量等;主线程分发
addTextListenerremoveTextListener文本;主线程分发
addVoiceListenerremoveVoiceListener远端 PCM;实时回调线程
addVoiceCaptureListenerremoveVoiceCaptureListener本地 PCM;主线程分发
addFileSendListenerremoveFileSendListener发送进度;主线程分发
addFileReceiveListenerremoveFileReceiveListener接收进度/最终字节;主线程分发

SDK 用强引用保存 listener。必须移除同一个实例,否则会重复回调并延长 Activity/ViewModel 生命周期。

API 接口参考 · 错误码与常见问题