最近公司頭戴換了一塊藍牙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 所已也走自定義協議。