Kotlin开发Android应用向STM32低功耗蓝牙设备发送Int数据问题求助
问题排查与解决方案
核心错误点
- 连接状态判断错误:现有代码中
isConnected标记的是手机本地蓝牙适配器的开关状态,不是你与目标BLE设备的GATT连接状态,即使蓝牙开启,未和目标设备建立GATT连接也无法写入数据 - 写入对象错误:如果你用的是Nordic Android BLE库,
ConfigCharacteristic是你用descriptorOf创建的描述符对象,写入特征值需要用characteristicOf创建特征值标识,而非使用描述符对象。如果用原生BLE API,需要获取BluetoothGattCharacteristic实例写入 - 混淆BLE与经典蓝牙逻辑:注释中使用
outputStream是经典蓝牙SPP协议的用法,BLE通信完全不适用该逻辑 - Int转字节数组方式错误:如果你要发送的是完整32位Int,
byteArrayOf(1)仅写入了1个字节,需要按设备要求的大小端规则转换完整Int为字节数组 - 未指定写入类型:BLE特征值写入需要匹配设备支持的写入类型(默认带响应/无响应),类型不匹配会写入失败
修正步骤
第一步:完成BLE设备GATT连接
你持有目标设备MAC地址,先建立GATT连接,原生API示例代码如下:
// 先根据MAC地址拿到BluetoothDevice对象 val targetDevice = bluetoothAdapter.getRemoteDevice("替换为你的目标设备MAC地址") // 建立GATT连接,autoConnect设为false为主动直连 var bluetoothGatt: BluetoothGatt? = null bluetoothGatt = targetDevice.connectGatt(context, false, gattCallback) // GATT连接回调 private val gattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { super.onConnectionStateChange(gatt, status, newState) if (newState == BluetoothProfile.STATE_CONNECTED) { // 连接成功后必须先发现服务,该步骤不可省略 gatt?.discoverServices() } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // 连接断开处理 settingViewModel.setIsBleDeviceConnected(false) gatt?.close() } } override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) { super.onServicesDiscovered(gatt, status) if (status == BluetoothGatt.GATT_SUCCESS) { // 服务发现成功后才可写入数据,更新BLE设备连接状态为true settingViewModel.setIsBleDeviceConnected(true) // 缓存目标特征值后续使用 val service = gatt?.getService(UUID.fromString(SERVICE_UUID)) val targetChar = service?.getCharacteristic(UUID.fromString("00E00000-0001-11e1-ac36-0002a5d5c51b")) settingViewModel.targetCharacteristic = targetChar } } override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { super.onCharacteristicWrite(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { // 写入成功回调 CoroutineScope(Dispatchers.Main).launch { Toast.makeText(context, "写入成功", Toast.LENGTH_SHORT).show() } } } }
第二步:添加Int转字节数组工具方法
根据你设备要求的大小端规则转换,下方为小端序转4字节Int示例:
fun Int.toByteArrayLittleEndian(): ByteArray { return byteArrayOf( (this and 0xFF).toByte(), (this shr 8 and 0xFF).toByte(), (this shr 16 and 0xFF).toByte(), (this shr 24 and 0xFF).toByte() ) }
第三步:修正按钮点击写入逻辑
Button( onClick = { // 此处判断的是BLE设备的GATT连接状态,不是蓝牙适配器开关状态 if (settingViewModel.isBleDeviceConnected.value == true && settingViewModel.targetCharacteristic != null) { val targetChar = settingViewModel.targetCharacteristic!! // 替换为你要发送的Int值 val sendInt = 100 val sendBytes = sendInt.toByteArrayLittleEndian() // 如果设备要求无响应写入,替换为WRITE_TYPE_NO_RESPONSE targetChar.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT targetChar.value = sendBytes coroutine.launch(Dispatchers.IO) { try { bluetoothGatt?.writeCharacteristic(targetChar) } catch (e: Exception) { CoroutineScope(Dispatchers.Main).launch { Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show() } } } } } ) { Text(text = "发送数据") }
额外注意事项
- 安卓12及以上版本需要申请
BLUETOOTH_SCAN、BLUETOOTH_CONNECT动态权限,未获取权限会调用失败 - 写入操作必须在
onServicesDiscovered回调之后执行,提前调用必然失败 - 可先打印
targetChar.properties确认目标特征值是否支持写入,需包含BluetoothGattCharacteristic.PROPERTY_WRITE或者PROPERTY_WRITE_NO_RESPONSE属性
内容的提问来源于stack exchange,提问作者Mehdi.ncb
相关产品推荐
相关产品推荐

