因为之前有做与蓝牙有关的项目,所以这里写个博客总结一下。
附带了一个项目以供参考:https://github.com/979451341/BleStudy
1.获取蓝牙服务
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
2.开启蓝牙
mBluetoothAdapter.enable();
3.搜索蓝牙设备
var mScanCallback = object :ScanCallback(){
override fun onScanResult(callbackType: Int, result: ScanResult?) {
}
}
mBluetoothLeScanner.startScan(mScanCallback)
4.连接蓝牙设备
//首先获取设备
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
//建立连接获取BluetoothGatt对象,并设置监听
gatts = device.connectGatt(instance, false, mGattCallback);
首先说说BluetoothGatt对象,他是蓝牙通信的协议,连接蓝牙设备,发现服务,向蓝牙设备传数据和接收蓝牙设备的数据,都需经过他。
然后我们通过BluetoothGattCallback的,来监听这些过程。
private static BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (BluetoothGatt.GATT_SUCCESS == status) {
//开启监听成功,可以像设备写入命令了
}
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
//连接成功
Log.e(TAG, "设备连接上 开始扫描服务");
boolean discoverServices = gatt.discoverServices();
if (discoverServices) {
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//发现服务
String address = gatt.getDevice().getAddress();
//绑定特征
bindCharas(address, getSupportedGattServices(address));
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//characteristic.getValue()为设备发送的数据,根据数据协议进行解析,对应onCharacteristicRead
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// characteristic.getValue()为设备发送的数据,根据数据协议进行解析,对应onCharacteristicChanged
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.e(TAG, "发送成功");
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
};
其中绑定特征需要详细说说,一个蓝牙设备有多个BluetoothGattService服务,一个服务有多个BluetoothGattCharacteristic特征,一个特征有多个BluetoothGattDescriptor描述。
其中我们是通过UUID来区别特征,这个由硬件工程师提供。
我们刚连接蓝牙,需要获取蓝牙设备传过来的数据。首先获取 read的特征,然后获取 通知描述,并给 mBluetoothGatt,使其知道我们需要接受通知
//获取服务
mBluetoothGatt.getServices()
//获取read特征
private static void bindCharas(String address, List gattServices) {
for (BluetoothGattService gattService : gattServices) {
List gattCharacteristics = gattService.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
String uuid_str = gattCharacteristic.getUuid().toString();
if (uuid_str.equalsIgnoreCase(Constant.SMART_TAG_READ_UUID)) {
BluetoothGattCharacteristic mReadCharacteristic = gattCharacteristic;
setCharacteristicNotification(address, mReadCharacteristic, true);
}
}
}
}
5.手机传送命令
首先获取write特征
for (BluetoothGattService gattService : mBluetoothGatt.getServices()) {
uuid = gattService.getUuid().toString();
List gattCharacteristics = gattService.getCharacteristics();
// Loops through available Characteristics.
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
uuid = gattCharacteristic.getUuid().toString();
if (uuid.equalsIgnoreCase(Constant.SMART_TAG_WRITE_UUID)) {
return gattCharacteristic;
}
}
}
然后给特征赋值,给gatt发出命令
boolean write = characteristic.setValue(cmd);
mBluetoothGatt.writeCharacteristic(characteristic);
6.断开蓝牙
在我们退出应用时,需断开连接
gatts.disconnect();
gatts.close();
二.蓝牙通信如何写入项目
1.蓝牙通信模块放哪
我们需要将蓝牙通信模块放在一个生命周期和应用相当的对象里,比如Application,不过这个类承担了很多sdk初始化的任务,所以我认为应该交给Service。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, BleService::class.java))
} else {
startService(Intent(this, BleService::class.java))
}
2.数据分发
在Service里初始化蓝牙服务,在BluetoothGattCallback里监听蓝牙连接的状况,并通过EventBus发送出去,也可以通过广播发送出去,我认为EventBus写的代码少一些好用一些。
3.蓝牙重连和心跳包
在service的onCeate函数里,使用Handler或TimerTask完成这个任务
4.连接多蓝牙设备
需区分设备
参考文献
https://juejin.im/post/599b8388f265da249600bbfd
作者:键盘舞者113