You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 18:54:03