Android BluetoothGattServer向多台已连接设备同步发送数据的解决方案咨询
Android BLE GATT服务端多设备同步发送流数据解决方案
Android原生蓝牙框架未提供和iOS peripheralManager.updateValue 对等的批量设备发送API,可通过以下方案实现需求:
方案1:独立设备发送队列 + 回调驱动分片发送(兼容性最好,全Android版本可用)
为每个已连接设备维护独立的待发送分片队列,重写BluetoothGattServerCallback的onNotificationSent方法,回调触发后立即给对应设备发送下一个分片,不同设备的发送流程互不阻塞,最大化发送效率。
示例代码:
// 每个设备对应一个发送队列 private ConcurrentHashMap<BluetoothDevice, ConcurrentLinkedQueue<byte[]>> deviceSendQueues = new ConcurrentHashMap<>(); // 记录每个设备是否正在等待发送回调 private ConcurrentHashMap<BluetoothDevice, Boolean> deviceIsSending = new ConcurrentHashMap<>(); // 初始化时给新连接的设备创建队列 @Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { super.onConnectionStateChange(device, status, newState); if (newState == BluetoothProfile.STATE_CONNECTED) { mServerActionListener.addDevice(device); deviceSendQueues.put(device, new ConcurrentLinkedQueue<>()); deviceIsSending.put(device, false); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { mServerActionListener.removeDevice(device); deviceSendQueues.remove(device); deviceIsSending.remove(device); } } // 批量提交待发送数据给所有设备 public void sendDataToAllDevices(byte[] data, UUID characteristicUuid) { // 先按当前协商的MTU分片,一般MTU减3是单包最大载荷 int mtu = 512; // 可以替换为实际协商的MTU值 int chunkSize = mtu - 3; List<byte[]> chunks = splitDataToChunks(data, chunkSize); for (BluetoothDevice device : mDevices) { deviceSendQueues.get(device).addAll(chunks); // 如果设备当前没在发送,触发发送流程 if (!deviceIsSending.get(device)) { sendNextChunk(device, characteristicUuid); } } } // 给指定设备发送下一个分片 private void sendNextChunk(BluetoothDevice device, UUID characteristicUuid) { ConcurrentLinkedQueue<byte[]> queue = deviceSendQueues.get(device); if (queue == null || queue.isEmpty()) { deviceIsSending.put(device, false); return; } byte[] chunk = queue.poll(); BluetoothGattCharacteristic characteristic = mGattServer.getService(SERVICE_UUID).getCharacteristic(characteristicUuid); characteristic.setValue(chunk); boolean confirm = BluetoothUtils.requiresConfirmation(characteristic); deviceIsSending.put(device, true); mGattServer.notifyCharacteristicChanged(device, characteristic, confirm); } // 回调触发后发送下一个分片 @Override public void onNotificationSent(BluetoothDevice device, int status) { super.onNotificationSent(device, status); if (status == BluetoothGatt.GATT_SUCCESS) { sendNextChunk(device, YOUR_CHARACTERISTIC_UUID); } } // 数据分片工具方法 private List<byte[]> splitDataToChunks(byte[] data, int chunkSize) { List<byte[]> chunks = new ArrayList<>(); int length = data.length; for (int i = 0; i < length; i += chunkSize) { int end = Math.min(length, i + chunkSize); chunks.add(Arrays.copyOfRange(data, i, end)); } return chunks; }
方案2:使用BLE L2CAP CoC通道(适合大流数据传输,Android 10及以上支持)
如果你的应用适配Android 10及以上版本,可使用L2CAP面向连接通道(Connection Oriented Channel)传输流数据,该通道原生支持流式传输,不需要手动拆分特征通知,吞吐量远高于特征值通知,且支持多设备同时独立传输。
核心调用API:
// 服务端开启L2CAP通道 int psm = mBluetoothManager.openL2capServer(/* 加密/传输参数 */); // 客户端连接对应PSM即可获得输入输出流,直接读写流数据
方案3:使用无响应通知批量提交(Android 12及以上优化)
如果你使用的是不需要确认的NOTIFICATION类型(confirm = false),Android 12及以上版本的蓝牙栈优化了发送队列逻辑,你可以直接批量调用notifyCharacteristicChanged,底层会自动排队发送,不需要上层等待回调,性能接近iOS批量发送的体验。
内容的提问来源于stack exchange,提问作者Muneer
相关产品推荐
相关产品推荐

