蓝牙Gatt连接
项目地址:gitee.com/bluetooth
这个项目包含多个Android模块,其中的test2模块就是蓝牙Gatt功能。
此项目只是一个测试的demo,如果要测试Gatt蓝牙连接的代码可以看看。
一、蓝牙Gatt连接步骤:
当时不清楚Gatt连接的流程是什么,所以写了很多冗余代码,后面也没有抽出时间去优化。 在这里写一下核心的代码分析。(项目中的Gatt蓝牙连接代码是从网上的demo修改来的, 对蓝牙数据的处理部分是实际项目中的)。
数据处理部分:1.发送Gatt数据前字符串太长的话需要对字符串进行截取,分段发送。
2.每次得到返回的Gatt数据后需要获取其中的标志和有用信息保存起来
1.连接步骤:
- 0.确定要连接的蓝牙设备的
Mac地址 - 1.扫描到目标蓝牙设备,得到
BluetoothDevice mSelectedDevice对象。 - 2.使用
mSelectedDevice.connectGatt(context,false,mGattCallback)进行Gatt连接。 - 3.在
BluetoothGattCallback mGattCallback里面获取Gatt-Service服务,从服务中获取BluetoothGattCharacteristic mVIDPIDCharacteristicGatt特征值对象。 - 4.发送Gatt消息的时候使用
mBluetoothGatt.writeCharacteristic()BluetoothGattCharacteristic RxChar...; RxChar.setValue(); mBluetoothGatt.writeCharacteristic(RxChar) - 5.蓝牙设备返回的Gatt消息
BluetoothGattCallback mGattCallback => onCharacteristicChanged监听的方法中获取。
二.详细的Gatt核心代码逻辑
因为MainActivity和TestActivity中代码都比较多,都有一些必要的代码所以没有将两个代码放到一块。
1.代码逻辑
- 1.进入
MainActivity页面后,首先获取定位权限,打开手机蓝牙。定义目标蓝牙设备的Mac地址private String MAC = "54:6C:0E:35:78:18"; - 2.点击
开始搜索按钮后,执行蓝牙扫描操作,注册广播监听蓝牙扫描回调。在扫描到蓝牙后判断是目标蓝牙后,携带BluetoothDevice device参数跳转到TestActivity页面。 - 3.在
TestActivity页面使用BluetoothDevice mSelectedDevice接收传过来的蓝牙对象。在onResume方法里面执行connectGatt逻辑。需要定义Gatt服务的各个Id值如:RX_SERVICE_UUID、RX_CHAR_UUID、RX_CHAR_UUID_DSC、RX_DESC_UUID、RX_DESC_UUID_DES- 3.1使用
mBluetoothGatt = mSelectedDevice.connectGatt(mContext, false, mGattCallback)进行Gatt连接 - 3.2在
BluetoothGattCallback mGattCallback回调中获取Gatt连接信息及真正的Gatt连接操作。- 3.2.1在
onConnectionStateChange方法判断Gatt连接状态if (status == BluetoothGatt.GATT_SUCCESS) {} - 3.2.2在
onServicesDiscovered方法中获取Gatt-Service服务List<BluetoothGattService> services = gatt.getServices(); - 3.3.3在使用Gatt-Service的特征值连接时需要:ServiceId:
RX_SERVICE_UUID、CharaId:RX_CHAR_UUID_DSC、DescriptorId:RX_CHAR_UUID_DSC。最后取到BluetoothGattDescriptor descriptor,使用mBluetoothGatt.writeDescriptor(descriptor);进行真正的连接。 - 3.3.4在
onDescriptorWrite方法中监听连接状态,这里的连接成功才是真正的连接成功!
- 3.2.1在
- 3.1使用
- 4.点击
发送消息按钮,处理数据后使用sendData(byte[] value)方法执行发送Gatt数据的逻辑,在onCharacteristicWrite回调方法中可以监听到发送的数据。在onCharacteristicRead方法没有实际作用。 - 5.在
onCharacteristicChanged回调方法中获取从蓝牙设备返回的数据,对返回的数据做处理。
三.其他代码分析
如果要使用MainActivity页面的一些代码,要注意的是:
在配置
private String MAC = "54:6C:0E:35:78:18";蓝牙Mac地址后,如果扫描到目标蓝牙会直接跳到TestActivity的问题。
主要在MainActivity中:
- 1.获取定位权限及回调
private void requestPermission() { if (Build.VERSION.SDK_INT >= 23) { int checkAccessFinePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION); if (checkAccessFinePermission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_ACCESS_LOCATION); Log.e(getPackageName(), "没有权限,请求权限"); return; } Log.e(getPackageName(), "已有定位权限"); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case 1: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.e(getPackageName(), "开启权限permission granted!"); } else { Log.e(getPackageName(), "没有定位权限,请先开启!"); Toast.makeText(this, "权限没有开启!", Toast.LENGTH_SHORT).show(); } } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } - 2.打开蓝牙功能
private boolean openBluetooth(BluetoothAdapter blueToothClient) { if (blueToothClient != null && !blueToothClient.isEnabled()) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, REQUEST_OPEN_BT_CODE); return false; } return true; } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_OPEN_BT_CODE) { Boolean success = resultCode == RESULT_OK; showToast(success ? "打开蓝牙成功!" : "打开蓝牙失败!"); if (success) search(null); if (success) getBindDevice(null); } } - 3.对列表蓝牙操作弹窗
DeviceActionFragment - 4.点击蓝牙列表中的连接蓝牙,先进行
蓝牙绑定操作。BleHelper.bond(device);- 4.1在配对的情况下进行数据传输,这里使用蓝牙手机、蓝牙耳机测试一直有问题。
BleHelper.connectDevice(blueToothClient, device, MainActivity.this);
- 4.1在配对的情况下进行数据传输,这里使用蓝牙手机、蓝牙耳机测试一直有问题。
- 5.如果知道目标蓝牙的
Pin码的话,在上面绑定的过程中会拦截蓝牙Pin配对过程直接使用代码进行配对连接。 - 6.蓝牙断开连接,在
DeviceActionFragment中。Boolean remove = BleHelper.removeBonds(bluetoothDevice); Toast.makeText(this.getActivity(), remove ? "断开成功!" : "断开失败!", Toast.LENGTH_SHORT).show();