Android 蓝牙 BLE 开发笔记
最近公司头戴换了一块蓝牙4.0 BLE模块,所以我们Android组要适配 BLE。
Android BLE 需要 4.3 以上系统,api 还是非常简单的, 第一步就是扫描, 扫描到设备后就可以连接了,
连接成功后在 onServicesDiscovered 中拿到 Service Characteristic Descriptor 就可以了。
不过还是遇到了几个小坑
第一: setCharacteristicNotification 时 onCharacteristicChanged 中收不到回调 原因是 BLE 不能连续执行写操作,必须等前一个
写完了再写一下个, 所以应该维护一个队列等前一个写完了再写下一个。
启用通知
BluetoothGattCharacteristic rxCharacteristic = uartService .getCharacteristic(UUID.fromString(BleConst.UUID_RX_CHARACTERISTIC)); if (rxCharacteristic != null) { BluetoothGattDescriptor rxCharacteristicDescriptor = rxCharacteristic .getDescriptor(UUID.fromString(BleConst.UUID_RX_CHARACTERISTIC_DESCRIPTOR)); // 设置 Characteristic 可以接收通知 gatt.setCharacteristicNotification(rxCharacteristic, true); if (rxCharacteristicDescriptor != null) { // enable descriptor notification rxCharacteristicDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(rxCharacteristicDescriptor); } }
第二:蓝牙自动配对
自动配对就是通过反射去调用 BluetoothDevice 的 createBond 方法
Method createBondMethod = BluetoothDevice.class.getMethod("createBond"); createBondMethod.invoke(btDevice);
第三:蓝牙自动连接
配对和连接是不一样的,自动配对后还要连接上蓝牙, stackoverflow 查了一些下面的方法可以自动连接 A2DP 和 HFP 两个 profile
监听 BluetoothDevice.ACTION_BOND_STATE_CHANGED 广播,蓝牙配对成功后调用下面的方法连接上两个 profile 就行了。
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); adapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { try { Log.d(TAG, "a2dp onServiceConnected"); Method connect = BluetoothA2dp.class.getDeclaredMethod("connect", BluetoothDevice.class); connect.invoke(proxy, device); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(int profile) { Log.d(TAG, "a2dp onServiceDisconnected"); } }, BluetoothProfile.A2DP); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); adapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { try { Log.d(TAG, "hfp onServiceConnected"); Method connect = BluetoothHeadset.class.getDeclaredMethod("connect", BluetoothDevice.class); connect.invoke(proxy, device); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(int profile) { Log.d(TAG, "hfp onServiceDisconnected"); } }, BluetoothProfile.HEADSET);
目前头戴所有按键走的都是蓝牙自定义协议,本来Android是可以用 HID 标准键值的, 但由于 IOS 不支持 HID 所已也走自定义协议。