| | |
| | | @Override |
| | | public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { |
| | | Log.d(TAG, "onCharacteristicChanged: " + characteristic.getUuid()); |
| | | |
| | | //收到蓝牙回复的数 |
| | | if (characteristic.getUuid().equals(notifyCharUuid) && writeListener != null) { |
| | | byte[] value = characteristic.getValue(); |
| | | // Log.d(TAG, "打印十六进制: " + bytesToHexString(value)); |
| | | String response = new String(value, StandardCharsets.UTF_8); |
| | | callbackHandler.post(() -> writeListener.onDeviceResponse(response)); |
| | | } |
| | |
| | | // 第 1 步:在协议栈层面开启通知 |
| | | boolean enabled = bluetoothGatt.setCharacteristicNotification(characteristic, true); |
| | | if (enabled) { |
| | | // 根据 Android 版本和设备厂商动态调整延迟 |
| | | int delayMs = calculateNotificationDelay(); |
| | | callbackHandler.postDelayed(() -> { |
| | | |
| | | // 第 2 步:获取客户端特征配置描述符 (CCCD) |
| | | // ↑ 00002902 是标准的 CCCD 描述符 UUID |
| | | BluetoothGattDescriptor descriptor = characteristic.getDescriptor( |
| | |
| | | if (descriptor != null) { |
| | | // // 第 3 步:设置描述符的值 |
| | | // // 先检查特征属性,决定使用 NOTIFY 还是 INDICATE |
| | | // int charProp = characteristic.getProperties(); |
| | | // if ((charProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { |
| | | // descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); |
| | | // Log.d(TAG, "使用 NOTIFICATION 模式"); |
| | | // } else if ((charProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) { |
| | | // descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); |
| | | // Log.d(TAG, "使用 INDICATION 模式"); |
| | | // } else { |
| | | // Log.e(TAG, "该特征不支持通知/指示"); |
| | | // return; |
| | | // } |
| | | int charProp = characteristic.getProperties(); |
| | | if ((charProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { |
| | | descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); |
| | | Log.d(TAG, "使用 NOTIFICATION 模式"); |
| | | } else if ((charProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) { |
| | | descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); |
| | | Log.d(TAG, "使用 INDICATION 模式"); |
| | | } else { |
| | | Log.e(TAG, "该特征不支持通知/指示"); |
| | | return; |
| | | } |
| | | // 第 3 步:设置描述符的值为 ENABLE_NOTIFICATION_VALUE, |
| | | // ↑ 这个值是 byte[]{0x01, 0x00},告诉设备端"我要订阅通知" |
| | | descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); |
| | | // descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); |
| | | // 第 4 步:写入描述符到设备 |
| | | //↑ 只有写入成功后,告诉设备端,设备才会开始发送通知, |
| | | bluetoothGatt.writeDescriptor(descriptor); |
| | | |
| | | Log.d(TAG, "writeDescriptor success"); |
| | | } |
| | | }, delayMs); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) |
| | | private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String value) { |
| | | |
| | | Log.d(TAG, "writeCharacteristic :开始写入"); |
| | | if (!this.getMissingPermissions().isEmpty()) { |
| | | callbackHandler.post(() -> this.writeListener.onWriteFailed(-2)); // 没有权限 |
| | |
| | | Log.d(TAG, "writeCharacteristic :开始完成"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据 Android 版本和设备厂商计算延迟时间 |
| | | * Android 10/11 不需要延迟 原因:系统处理快,无严格检查 |
| | | * Android 12 需要100-200ms延迟 原因:系统需要时间准备 BLE 协议栈 |
| | | * Android 13 需要50-100ms延迟 原因:优化后速度稍快 |
| | | * Android 14 需要50ms延迟 原因:进一步优化 |
| | | */ |
| | | private int calculateNotificationDelay() { |
| | | int sdkVersion = Build.VERSION.SDK_INT; |
| | | |
| | | // Android 12 (SDK 31) 需要最长延迟 |
| | | if (sdkVersion == Build.VERSION_CODES.S) { |
| | | // 小米/红米设备可能需要更长延迟 |
| | | if ("Xiaomi".equals(Build.MANUFACTURER)) { |
| | | Log.d(TAG, "检测到小米设备,增加延迟到 200ms"); |
| | | return 200; |
| | | } |
| | | // 其他 Android 12 设备 |
| | | return 100; |
| | | } |
| | | |
| | | // Android 13+ 优化后延迟可以短一些 |
| | | if (sdkVersion >= Build.VERSION_CODES.TIRAMISU) { |
| | | return 50; |
| | | } |
| | | |
| | | // Android 11 及以下不需要延迟 |
| | | return 0; |
| | | } |
| | | |
| | | // ==================== 工具方法 ==================== |
| | | |
| | | /** |