蓝牙DFU升级发现红米手机可以发送成功,但是荣耀手机、华为手机都执行无返回响应。请求大佬们解答求求了,这个发送问题卡我好几天了。
源码:testSendInitPacket() {
let _this = this
this.downloadFirmware().then(() => _this.connectToDevice())
.then(() => _this.enableNotify())
.then(() => {
return new Promise((resolve, reject) => {
let _this = this
console.log('setBLEMTU 开始')
// 设置MTU
uni.setBLEMTU({
deviceId: _this.deviceId,
mtu: _this.mtuSize,
success(res) {
console.log('MTU协商: 请求=' + _this.mtuSize)
_this.addDfuLog('MTU协商完成', true)
setTimeout(() => {
console.log('setBLEMTU 结束')
resolve()
}, 1000)
},
fail(err) {
_this.addDfuLog('MTU协商失败: ' + (err.errMsg || JSON.stringify(err)))
console.log('MTU协商失败: ' + (err.errMsg || JSON.stringify(err)))
setTimeout(() => {
reject()
}, 1000)
}
})
})
}).then(() => {
return new Promise((resolve, reject) => {
resolve(_this.testStep1())
})
})
},
// ========== 测试用例:先擦除再发init包(严格按官方流程) ==========
// 参考官方流程:Validate.java 先 performer.enqueue(new Erase(...)) 再 enqueue(new Upload(...))
testStep1() {
let _this = this
_this.addDfuLog('【测试】Step 1: 发送擦除命令...', true)
console.log('【测试】testStep1: 发送擦除命令')
_this.dfuSequenceNumber++
// 官方行为:slot=SECONDARY时payloadMap为null,在buildPacket中转为new HashMap<>(),
// CBOR.toBytes(new HashMap<>()) → 0xA0(空CBOR map,1字节)
// 注意:必须是0xA0(1字节有效CBOR),不能是0字节的空ArrayBuffer
const eraseCbor = new Uint8Array([0xA0]).buffer
const eraseFrame = buildSmpFrame(0x01, 0x05, eraseCbor, _this.dfuSequenceNumber)
_this.addDfuLog('【测试】擦除命令帧=' + ab2hex(eraseFrame))
// 设置擦除响应回调
_this.dfuEraseCallback = (response) => {
const rc = response.rc !== undefined ? response.rc : 0
if (rc === 0) {
_this.addDfuLog('【测试】擦除成功,开始发送init包...', true)
console.log('【测试】testStep1: 擦除成功,发送init包')
_this.dfuEraseCallback = null
// 擦除成功后发送init包
_this.doTestSendInit()
} else {
_this.addDfuLog('【测试】擦除失败(rc=' + rc + ')', false, true)
_this.dfuEraseCallback = null
}
}
_this.doTestSend(eraseFrame, 30000, 'dfuEraseCallback')
},
doTestSendInit() {
let _this = this
_this.addDfuLog('【测试】Step 2: 构建init包并发送...', true)
const firmwareDataView = new Uint8Array(_this.dfuFirmwareBuffer)
const firmwareSize = firmwareDataView.length
let currentOffset = 0
let sentChunks = 0
let uploadResolved = false
const initResult = buildCborInitUpload(firmwareDataView, _this.dfuFirmwareHash, _this
.mtuSize)
_this.dfuSequenceNumber++
const frame = buildSmpFrame(0x01, 0x01, initResult.cborBuffer, _this.dfuSequenceNumber)
const frameHex = ab2hex(frame)
const frameSize = frame.byteLength
const attLimit = _this.mtuSize - 3
_this.addDfuLog('【测试】init包=' + frameSize + '字节, ATT上限=' + attLimit + '字节')
console.log('【测试】init包=' + frameSize + '字节, ATT上限=' + attLimit + ', hex=' + frameHex)
if (frameSize > attLimit) {
_this.addDfuLog('【测试】init包超过ATT上限,无法发送', false, true)
return
}
_this.doTestSend(frame, 120000, 'dfuInitResponseCallback')
},
doTestSend(buffer, timeoutMs = 10000, callbackType = 'dfuInitResponseCallback') {
let _this = this
const startTime = Date.now()
let responded = false
_this.addDfuLog('【测试】正在发送测试包(' + buffer.byteLength + '字节, 回调=' + callbackType + ')...')
// 设置临时响应回调(支持擦除回调和init回调)
const origInitCallback = _this.dfuInitResponseCallback
const origEraseCallback = _this.dfuEraseCallback
// 接管指定回调
if (callbackType === 'dfuInitResponseCallback') {
_this.dfuInitResponseCallback = (rc) => {
responded = true
const elapsed = Date.now() - startTime
_this.addDfuLog('【测试】收到init响应 rc=' + rc + ', 耗时=' + elapsed + 'ms', rc === 0)
console.log('【测试】doTestSend: 收到init响应 rc=' + rc + ', 耗时=' + elapsed + 'ms')
_this.dfuInitResponseCallback = origInitCallback
}
} else if (callbackType === 'dfuEraseCallback') {
_this.dfuEraseCallback = (response) => {
responded = true
const elapsed = Date.now() - startTime
const rc = response.rc !== undefined ? response.rc : 0
_this.addDfuLog('【测试】收到擦除响应 rc=' + rc + ', 耗时=' + elapsed + 'ms', rc === 0)
console.log('【测试】doTestSend: 收到擦除响应 rc=' + rc + ', 耗时=' + elapsed + 'ms')
// 调用原始测试回调(由testStep1设置)
if (origEraseCallback) {
origEraseCallback(response)
}
}
}
// 写类型日志
const wType = getWriteType()
console.log('【测试】doTestSend: 写类型=' + wType + ', 超时=' + timeoutMs + 'ms')
uni.writeBLECharacteristicValue({
deviceId: _this.deviceId,
serviceId: _this.smpServiceId,
characteristicId: _this.smpCharacteristicId,
value: buffer,
writeType: wType,
success: () => {
const writeElapsed = Date.now() - startTime
_this.addDfuLog('【测试】写入成功,等待设备响应...')
console.log('【测试】doTestSend: 写入成功, 写入耗时=' + writeElapsed + 'ms, 等待响应中...')
// 超时处理
setTimeout(() => {
if (!responded) {
_this.addDfuLog('【测试】' + timeoutMs + 'ms超时,设备未响应', false, true)
console.log('【测试】doTestSend: 超时=' + timeoutMs + 'ms, 无响应')
if (callbackType === 'dfuInitResponseCallback') {
_this.dfuInitResponseCallback = origInitCallback
}
}
}, timeoutMs)
},
fail: (err) => {
_this.addDfuLog('【测试】写入失败: ' + err.errMsg, false, true)
console.log('【测试】doTestSend: 写入失败: ' + err.errMsg)
if (callbackType === 'dfuInitResponseCallback') {
_this.dfuInitResponseCallback = origInitCallback
}
}
})
},
跟踪日志:16:44:04.605 parseImageHash: 成功提取哈希: 2b30932216faff7b1e983dc7dc34681045ed8ce966ef3f3f1a383fcd45dfe6fc at pages/ble-debug/utils/smp.js:205
16:44:04.605 从固件尾部 TLV 提取的哈希: 2b30932216faff7b1e983dc7dc34681045ed8ce966ef3f3f1a383fcd45dfe6fc at pages/ble-debug/dfu-upgrade.vue:1030
16:44:07.550 设备 CC:6A:26:AB:FC:31 连接状态变化, 已连接: {"deviceId":"CC:6A:26:AB:FC:31","connected":true} at pages/ble-debug/dfu-upgrade.vue:211
16:44:08.588 setBLEMTU 开始 at pages/ble-debug/dfu-upgrade.vue:784
16:44:08.634 MTU协商: 请求=150 at pages/ble-debug/dfu-upgrade.vue:792
16:44:09.608 setBLEMTU 结束 at pages/ble-debug/dfu-upgrade.vue:795
16:44:10.609 queryFirmwareState 开始 at pages/ble-debug/dfu-upgrade.vue:1043
16:44:10.609 发送镜像状态查询命令... at pages/ble-debug/dfu-upgrade.vue:1099
16:44:10.640 状态查询命令发送成功, writeType:, write at pages/ble-debug/dfu-upgrade.vue:1112
16:44:10.873 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:10.873 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:10.997 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 ========onBLECharacteristicValueChange进来了========== at pages/ble-debug/dfu-upgrade.vue:484
16:44:11.030 handleSmpResponse2进来了 at pages/ble-debug/dfu-upgrade.vue:540
16:44:11.030 接收 op=1, groupId=1, cmdId=0, payloadLen=134 at pages/ble-debug/dfu-upgrade.vue:563
16:44:11.030 收到结果:, {"images":[{"slot":0,"version":"1.0.1","hash":"710EA129F48437AADBF51D0B9EEF99A598A04BAE4A3ED50CCC53CBEA340A9B3E","bootable":true,"pending":false,"confirmed":true,"active":true,"permanent":false}],"splitStatus":0} at pages/ble-debug/dfu-upgrade.vue:570
16:44:11.030 接收: 通用捕获器调用 dfuStateCallback, rc=undefined, groupId=1, cmdId=0 at pages/ble-debug/dfu-upgrade.vue:593
16:44:11.030 queryFirmwareState: 设备哈希=710ea129f48437aadbf51d0b9eef99a598a04bae4a3ed50ccc53cbea340a9b3e, BIN哈希=2b30932216faff7b1e983dc7dc34681045ed8ce966ef3f3f1a383fcd45dfe6fc at pages/ble-debug/dfu-upgrade.vue:1059
16:44:11.030 queryFirmwareState 结束 at pages/ble-debug/dfu-upgrade.vue:1073
16:44:15.038 startFirmwareUpload 开始 at pages/ble-debug/dfu-upgrade.vue:822
16:44:15.039 startFirmwareUpload: 当前mtuSize=150, 固件大小=208464字节 at pages/ble-debug/dfu-upgrade.vue:1151
16:44:15.039 buildCborInitUpload: mtuSize=150, maxFrameSize=147, combinedSize=71, maxDataLength=76, maxDataHeaderSize=2, firstChunkSize=74 at pages/ble-debug/utils/cbor.js:203
16:44:15.039 buildCborInitUpload: CBOR载荷长度=134, 总帧大小(含SMP头)=142, ATT MTU限制=150 (ATT负载=147) at pages/ble-debug/utils/cbor.js:218
16:44:15.039 startFirmwareUpload: 帧大小=142, ATT上限=147, 超出=否 at pages/ble-debug/dfu-upgrade.vue:1166
16:44:15.039 命令帧=0a00008600010401a46464617461584a3db8f3960000000000080000b825030000000000010002000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff636c656e1a00032e50636f6666006373686158202b30932216faff7b1e983dc7dc34681045ed8ce966ef3f3f1a383fcd45dfe6fc at pages/ble-debug/dfu-upgrade.vue:1177
16:44:15.064 cmd=1 上传初始化发送成功,等待设备确认... at pages/ble-debug/dfu-upgrade.vue:1183
16:44:15.065 startFirmwareUpload: 设置 dfuInitResponseCallback at pages/ble-debug/dfu-upgrade.vue:1184
16:44:22.683 ========onBLEConnectionStateChange进来了========== at pages/ble-debug/dfu-upgrade.vue:492
16:44:22.683 dfu-upgrade: 设备断开连接, deviceId=CC:6A:26:AB:FC:31 at pages/ble-debug/dfu-upgrade.vue:496
1 个回复
Ask小助手 - Ask社区AI助手
根据你提供的代码和日志,结合知识库中的相关信息,这个问题很可能与
setBLEMTU在不同安卓机型上的兼容性差异有关。以下是分析和建议:问题分析
从日志看,状态查询命令(小数据包)可以正常发送和接收,但 init 包(142字节)发送后无响应。关键点在于:
setBLEMTU在荣耀/华为手机上可能没有真正生效,导致实际 MTU 仍为默认值 23(ATT 负载仅 20 字节),而你代码中按请求值 150 计算的 ATT 上限为 147,未对 142 字节的 init 包做分包处理,直接发送了超出实际承载能力的数据帧。可能原因
setBLEMTU 调用时机问题:根据社区反馈,部分安卓机型(包括华为)在
createBLEConnection成功后立即调用setBLEMTU会不生效或无响应。参考 ask社区问答 和 ask社区问答。MTU 实际协商值与请求值不一致:你代码中使用
this.mtuSize(请求值 150)计算 ATT 上限,但实际协商的 MTU 可能并非此值。根据 插件市场文档,Android 端蓝牙碎片化严重,不同机型表现不一致,部分机型setBLEMTU后实际 MTU 仍为默认 23。未监听 onBLEMTUChange:根据插件市场文档建议,连接设备前应先注册
onBLEMTUChange,因为连接成功后可能直接就协商好 MTU 了,未提前监听会错失通知。解决建议
setBLEMTU,或先发送一个小命令成功后再调用。参考 ask社区问答 中的方案:setBLEMTU成功后 MTU 就是请求值,应通过回调获取实际值:确认 writeType 设置:日志显示
writeType:为空,请确认getWriteType()返回的值是否正确。对于 DFU 升级场景,通常需要使用writeWithResponse(值为 1)确保数据可靠传输。MTU 值建议不超过 247:根据社区反馈,部分机型最大只支持 247,设置 512 等更大值会报错。参考 ask社区问答。
参考链接
如果以上方案仍无法解决跨机型兼容性问题,可以考虑使用插件市场的蓝牙 DFU 原生插件(如 dodo-uniplugin-ble 或 DFU蓝牙升级),原生插件在底层处理了各机型的蓝牙差异。
要回复问题请先登录或注册
公告
更多>相关问题