Android Studio新手求助:发送蓝牙十六进制命令`87`后无法接收数据(onCharacteristicChanged未触发)
Android Studio新手求助:发送蓝牙十六进制命令
87后无法接收数据(onCharacteristicChanged未触发) 嗨,我仔细看了你的代码,发现几个关键问题导致onCharacteristicChanged没触发,咱们一步步来修正:
先说说核心问题点
- 盲目遍历所有特征设置通知:你现在给每个遍历到的特征都加通知,不仅没必要,还可能把通知挂到错误的特征上,设备返回的数据根本没发到你监听的特征。
- CCCD描述符UUID用错:在
setNotify方法里你写了0000ffe1-...,但标准的客户端特征配置描述符(CCCD)UUID是固定的00002902-0000-1000-8000-00805f9b34fb,这个是BLE协议规定的,不能乱改。 - 变量作用域错误:
onServicesDiscovered末尾调用通知设置时,用的是循环最后一个characteristic变量,大概率不是你要操作的目标特征。 - 缺少发送
0x87的具体实现:sendSetting()是空的,没把十六进制命令转换成byte数组写入特征。
修改后的完整代码片段
首先先定义目标特征的UUID(这里一定要替换成你的蓝牙设备文档里指定的可写+通知特征UUID,比如常见的BLE串口特征是0000ffe1-0000-1000-8000-00805f9b34fb):
// 替换成你的设备实际的特征UUID private static final UUID TARGET_CHAR_UUID = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"); private BluetoothGattCharacteristic mTargetCharacteristic; // 保存目标特征,方便后续调用
然后修改BluetoothGattCallback里的关键方法:
BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @SuppressLint("MissingPermission") @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); Log.i(TAG, "onConnectionStateChange newstate:" + newState + " status:" + status); if (status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothProfile.STATE_CONNECTED) { Log.i(TAG, "============>GATT Connect Success!!<============="); mBluetoothGatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { if (mBluetoothGatt != null) { mBluetoothGatt.close(); mBluetoothGatt = null; mTargetCharacteristic = null; // 断开后清空特征引用 } } } } @SuppressLint("MissingPermission") @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); Log.i(TAG, "onServicesDiscovered(), status = " + status); if (status == BluetoothGatt.GATT_SUCCESS) { // 只找我们需要的目标特征,不要遍历所有特征 for (BluetoothGattService service : gatt.getServices()) { mTargetCharacteristic = service.getCharacteristic(TARGET_CHAR_UUID); if (mTargetCharacteristic != null) { Log.i(TAG, "找到目标特征:" + TARGET_CHAR_UUID); // 设置通知监听 setupNotification(mTargetCharacteristic); // 发送0x87命令 sendHexCommand(0x87); break; // 找到目标后直接退出循环 } } if (mTargetCharacteristic == null) { Log.w(TAG, "未找到目标特征,请检查UUID是否和设备文档一致"); } } else { Log.i(TAG, "onServicesDiscovered status false"); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value) { super.onCharacteristicChanged(gatt, characteristic, value); String receivedData = new String(value, StandardCharsets.UTF_8); Log.d(TAG, "Received data: " + receivedData); // 这里可以处理收到的数据,比如更新UI runOnUiThread(() -> { // 示例:显示收到的数据 // mTvReceived.setText("收到数据:" + receivedData); }); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); if(status == BluetoothGatt.GATT_SUCCESS){ Log.i(TAG,"onCharacteristicWrite status : " + status); Log.i(TAG,"value write success !!"); } else{ Log.i(TAG,"onCharacteristicWrite status : " + status); Log.w(TAG,"value write false !!"); } } // 其他回调方法(onCharacteristicRead)保留原逻辑即可 };
然后添加两个关键工具方法:
// 统一处理通知设置逻辑 @SuppressLint("MissingPermission") private void setupNotification(BluetoothGattCharacteristic characteristic) { // 打开特征通知开关 mBluetoothGatt.setCharacteristicNotification(characteristic, true); // 获取标准CCCD描述符 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); if (descriptor != null) { // 根据特征支持的类型选择通知/指示 if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); } else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); } // 写入描述符 boolean success = mBluetoothGatt.writeDescriptor(descriptor); Log.i(TAG, "设置通知:" + (success ? "成功" : "失败")); } else { Log.w(TAG, "该特征没有CCCD描述符,无法设置通知"); } } // 发送十六进制命令 @SuppressLint("MissingPermission") private void sendHexCommand(int hexValue) { if (mTargetCharacteristic == null) { Log.w(TAG, "目标特征为空,无法发送命令"); return; } // 检查特征是否支持写操作 if ((mTargetCharacteristic.getProperties() & (BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) == 0) { Log.w(TAG, "该特征不支持写操作"); return; } // 把十六进制87转换成byte数组 byte[] command = new byte[]{(byte) hexValue}; mTargetCharacteristic.setValue(command); // 写入特征(根据设备支持选择WRITE或WRITE_NO_RESPONSE) boolean success = mBluetoothGatt.writeCharacteristic(mTargetCharacteristic); Log.i(TAG, "发送命令0x87:" + (success ? "成功" : "失败")); }
最后别忘了检查权限:在AndroidManifest.xml里添加必要的蓝牙权限(针对Android 12+):
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
额外注意事项
- 一定要确认目标特征UUID:这个UUID必须和你的蓝牙设备厂商提供的文档一致,不能随便用示例UUID,否则找不到特征。
- 测试时看日志:如果还是没触发
onCharacteristicChanged,看日志里有没有“未找到目标特征”或“设置通知失败”的提示,排查问题。 - 设备是否主动发数据:有些设备需要收到命令后才会返回数据,确保你发送
0x87后设备确实有数据输出。
备注:内容来源于stack exchange,提问作者CXH
相关产品推荐
相关产品推荐

