不知不觉,通宵加班已经快两个星期了,快两年没这么干活了。
起因就是项目的一个功能,蓝牙多连接。应用同时连接多个设备,等待接收数据,处理后显示图表。
在这之前我没有搞过蓝牙方面的东西,只能从基础开始边看边干。
最开始不知道,看的是传统蓝牙的连接与传输,几天过后,发现与低功耗蓝牙不一样啊,又针对低功耗蓝牙开始找资料。
低功耗蓝牙支持的api最低是18。
基本思路:低功耗蓝牙连接分两种,一种是作为周边设备,一种是作为中心设备。因为需求是多连接,那我们就按照创建一个中心设备的做法来处理。
下面先记录一下,一个低功耗蓝牙的连接:
注:因为程序与硬件是一套设备,所以我不需要扫瞄附近的设备,然后选择连接,直接拿地址进行连接。
蓝牙需要的权限:
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
接下来在activity中,不管周边设备还是中心设备,我们都需要拿到:BluetoothManager和BluetoohAdapter:
//获取BluetoothManager BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); //获取BluetoothAdapter BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter(); //如果蓝牙没有打开 打开蓝牙 if (!mBluetoothAdapter.isEnabled()) { mBluetoothAdapter.enable(); }
然后就是通过上面拿到的adapter得到BluetoothDevice对象:
BluetoothDevice bluetoothDeviceOne = mBluetoothAdapter.getRemoteDevice("D8:B0:4C:BC:C0:83");
注:1.传入的参数就是你蓝牙的地址。
2.假如你需要多连接,那么这里就要获得多个BluetoothDevice对象,通过不同的地址。
然后就是BluetoothGatt对象:
private BluetoothGatt mBluetoothGattOne;
在拿到上面两个对象后,先校验gatt对象是否在运行:
//如果Gatt在运行,将其关闭 if (mBluetoothGattOne != null) { mBluetoothGattOne.close(); mBluetoothGattOne = null; }
然后就是连接设备,并设置连接的回调:
//连接蓝牙设备并获取Gatt对象 mBluetoothGattOne = bluetoothDeviceOne.connectGatt(MainActivity.this, true, bluetoothGattCallbackOne);
其中,bluetoothGattCallbackOne就是回调:
/** * 第一个设备 蓝牙返回数据函数 */ private BluetoothGattCallback bluetoothGattCallbackOne = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothProfile.STATE_CONNECTED) { setText("设备一连接成功"); //搜索Service gatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { setText("设备一连接断开"); } } super.onConnectionStateChange(gatt, status, newState); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { //根据UUID获取Service中的Characteristic,并传入Gatt中 BluetoothGattService bluetoothGattService = gatt.getService(UUID_SERVICE); BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattService.getCharacteristic(UUID_NOTIFY); boolean isConnect = gatt.setCharacteristicNotification(bluetoothGattCharacteristic, true); if (isConnect){ }else { Log.i("geanwen", "onServicesDiscovered: 设备一连接notify失败"); } super.onServicesDiscovered(gatt, status); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {//数据改变 super.onCharacteristicChanged(gatt, characteristic); String data = new String(characteristic.getValue()); Log.i("geanwen", "onCharacteristicChanged: " + data); } };
注:1.我的需求就是接收是蓝牙发送过来的数据,假如你需要写入数据,或者其他的功能,在上面的callback中,可以复写对应的方法。
2.上面onConectionStateChange方法就是连接状态改变时回调的方法,在其中判断连接是否成功。
3.上面onServicesDiscovered方法就是在onConectionStateChange连接成功之后,发现该蓝牙的服务。
在这里你可以设置你需要的服务,每个蓝牙连接中会有不同的服务,设置你需要的即可。
4.上面我设置了接收数据的服务,其中传入的几个常量就是我们低功耗蓝牙的服务的固定码,下面贴个例子:
//蓝牙设备的Service的UUID public final static UUID UUID_SERVICE = UUID.fromString("0003cdd0-0000-1000-8000-00805f9b0131"); //蓝牙设备的notify的UUID public final static UUID UUID_NOTIFY = UUID.fromString("0003cdd1-0000-1000-8000-00805f9b0131");
大家仔细看好,两个码是不一样的,一开始我以为是一样的,结果调了好久。
因为我这个需求是不能先搜索,在连接,然后选择对应服务的,所以我将这些这些操作都省略,即我提前拿到了这几个服务的码。
5.上面回调方法onCharacteristicChanged方法就是来数据了,接收的方法。
连接一个低功耗蓝牙并接收数据上面就介绍完了,下面说下连接两个或者多个。
首先上面提到了BluetoothDevice对象,连接两个时候,需要创建第二个:
BluetoothDevice bluetoothDeviceOne = mBluetoothAdapter.getRemoteDevice("D8:B0:4C:BC:C0:83"); BluetoothDevice bluetoothDeviceTwo = mBluetoothAdapter.getRemoteDevice("D8:B0:4C:BA:D5:9D");
下一步就是gatt对象了:
private BluetoothGatt mBluetoothGattOne; private BluetoothGatt mBluetoothGattTwo;
//连接蓝牙设备并获取Gatt对象 mBluetoothGattOne = bluetoothDeviceOne.connectGatt(MainActivity.this, true, bluetoothGattCallbackOne); mBluetoothGattTwo = bluetoothDeviceTwo.connectGatt(MainActivity.this, true, bluetoothGattCallbackTwo);
接下来就是在回调中等着了,同上面的callback没啥区别。
注:
1.上面说的方法,我同时连接了四个设备,可以同时接收到数据。
2.应用关闭后,在开启,有时会接收不到数据,具体问题时硬件还是软件正在调查。重启手机的蓝牙,过一会就好了。
3.上面的程序在华为手机上应该是不能成功,华为平板也不能。(蛋疼,目前我测试的手机是三星note2)
4.上述程序没有针对6.0及以上版本进行权限申请。
5.这篇文章是这几天找资料,东拼西凑试出来的,可能还有哪里有问题,欢迎童鞋们踊跃来指导,感激不尽。