问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Android BLE蓝牙开发详解

创作时间:
作者:
@小白创作中心

Android BLE蓝牙开发详解

引用
CSDN
1.
https://blog.csdn.net/weixin_39788742/article/details/146281244

BLE蓝牙技术是一种低功耗的蓝牙通信协议,在蓝牙4.0版本中引入的。与传统的经典蓝牙相比,BLE蓝牙技术在功耗、传输速度和传输距离等方面进行了优化,使其更适合用于物联网(IoT)等需要低功耗、低延迟和少量数据传输的应用场景。

概述

BLE蓝牙技术是一种低功耗的蓝牙通信协议,在蓝牙4.0版本中引入的。与传统的经典蓝牙相比,BLE蓝牙技术在功耗、传输速度和传输距离等方面进行了优化,使其更适合用于物联网(IoT)等需要低功耗、低延迟和少量数据传输的应用场景。

术语

  • 通用属性配置文件 (GATT):GATT 配置文件是一种通用规范,内容针对在 BLE链路上发送和接收称为“属性”的简短数据片段。所有最新的 BLE 应用配置文件都基于 GATT。
  • Characteristic(特征值):BLE设备上存储数据的基本单元,可以理解为一个数据类型。它包括一个value(值)和0至多个对此characteristic的描述(Descriptor)。
  • 描述符:对Characteristic的描述,如范围、单位等。它是可选的,并提供关于特征值的元数据。
  • Service(服务):Characteristic的集合,它可以包含多个Characteristic。每个BLE设备可以包含一个或多个服务,而每个服务又可以包含一个或多个特征值(Characteristic)。
  • UUID(通用唯一识别码):用于唯一标识BLE设备中的服务、特征值和描述符。UUID可以是标准的16位或128位,也可以是自定义的。
  • 通知(Notify)与指示(Indicate):这是BLE中两种用于数据更新的机制。当特征值的值发生变化时,外围设备可以向中心设备发送通知或指示。通知是单向的,可能无法保证可靠传递;而指示则具有确认机制,可以确保通知被接收。
  • MTU:在一个蓝牙数据包中能够传输的最大数据量。

使用

1.检查权限

Android不同系统版本对应蓝牙也会有差异,可以参考以下:

蓝牙权限设置

2.检查是否支持蓝牙

/*
* 设备是否支持蓝牙模块
*/
public boolean isSupportBle() {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2
                && context.getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
}

3.检查蓝牙是否打开,并打开

  • 首先获取蓝牙的BluetoothAdapter,有两种方式,分别如下:
//方式一
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//方式二
BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
  • 判断蓝牙是否打开
public boolean isBlueEnable() {
     return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
}
  • 如果没有打开蓝牙,则打开,使用enable()即可
public void enableBluetooth() {
    if (bluetoothAdapter != null) {
       bluetoothAdapter.enable();
    }
}

4.搜索蓝牙

通过bluetoothAdapter.getBluetoothLeScanner()获取BluetoothLeScanner来进行搜索。

BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
        bluetoothLeScanner.startScan(new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                super.onScanResult(callbackType, result);
                BluetoothDevice device = result.getDevice();//得到设备
                //可以通过对device中的数据与厂家做对比,例如广播出来的名字
            }
            @Override
            public void onBatchScanResults(List<ScanResult> results) {
                super.onBatchScanResults(results);
            }
            @Override
            public void onScanFailed(int errorCode) {
                super.onScanFailed(errorCode);
            }
        });

5.连接设备

可以通过connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback)来进行连接。

  • context:上下文。
  • autoConnect:false:代表直接连接到蓝牙设备,true代表在蓝牙设备可用时自动连接。
  • BluetoothGattCallback:是Gatt服务的回调。
BluetoothDevice device = result.getDevice();//这里的result是搜索时获取的设备数据,也可以根据需求传进来
device.connectGatt(this, false, new BleGattCallback() {
                  @Override
            device.connectGatt(this, false, new BluetoothGattCallback() {
                    
     @Override
                    public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
                        //写入Characteristic
                    }
                    @Override
                    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                        //读取Characteristic
                    }
                    @Override
                    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                        //写入Descriptor
                    }
                    @Override
                    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                        //读取Descriptor
                    }
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                        super.onConnectionStateChange(gatt, status, newState);
                        //连接状态改变
                        switch (newState){
                            //连接成功
                            case BluetoothProfile.STATE_CONNECTED:
                                break;
                            //连接断开
                            case BluetoothProfile.STATE_DISCONNECTED:
                                break;
                        }
                    }
                    @Override
                    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        //服务发现成功
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                        } else {
                        }
                    }
             
                    @Override
                    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                    //通知Characteristic
                    }
                });
     });

6.搜索服务

通过bluetoothGatt.discoverServices()来执行发现服务的操作,扫描到设备服务就会回调。

@Override
 public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        //服务发现成功
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                        } else {
                        }
                    }

7. 获取负责通信的BluetoothGattCharacteristic

通信主要通过BluetoothGattService来完成,以下是与硬件端沟通好的UUID值。

  • 通信服务中有负责读写的BluetoothGattCharacteristic,分别为notifyCharacteristic和writeCharacteristic。其中notifyCharacteristic也负责动收数据的通道,writeCharacteristic负责写入数据。
BluetoothGattService service = gatt.getService(UUID.fromString(UUID_SERVER));
notifyCharacteristic = service.getCharacteristic(UUID.fromString(UUID_NOTIFY));
writeCharacteristic =  service.getCharacteristic(UUID.fromString(UUID_WRITE));

8.开启监听

UUID是与硬件端确定,也只有把通道打开才能进行通信。


gatt.setCharacteristicNotification(notifyCharacteristic, true);
BluetoothGattDescriptor descriptor = characteristic .getDescriptor(UUID.fromString(""));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

并且会在onDescriptorWrite收到回调

@Override
 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
 
}

9.选择性设置mtu

mtu:(Maximum Transmission Unit,最大传输单元)是一个关键概念,它指的是在BLE连接中可以传输的最大数据包大小。

//根据需求设置mtu的大小
gatt.requestMtu()

在onMtuChanged可以获取回调

@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
   super.onMtuChanged(gatt, mtu, status);
   }

10.写入数据

data一般为16进制的数据,所以需要转换下数据格式

writeCharacteristic.setValue(data);
gatt.writeCharacteristic(writeCharacteristic);

在onCharacteristicWrite可以监听是否发送成功

  public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
                        //写入Characteristic
                    }

11. 接收数据

和设备交互,如果协议数据符合,则会收到来自设备端的数据,可以在onCharacteristicChanged监听获取。

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
 
}

12.断开连接

当设备与app不交互的时候,需要断开连接。

gatt.disconnect();
gatt.close();

广播数据

搜索蓝牙的时候,因为周围的手机、平板等的干扰跟多。我们可以通过广播出来的数据进行设备的筛选。数据包含长度,数据内容。我们根据长度对数据进行截取获取对应的内容并赋值。

注意点

  • 封装蓝牙工具类的时候,数据的传输可以通过EventBus来实现。
  • 数据过长,可以进行分包发送处理,例如协议数据包含数据长度,以及头部以及尾部的数据确定以进行拼接。
  • 常见会出现133的错误。
  1. 频繁连接设备:在断开连接的时候给一个缓冲时间,并且清除缓存
  2. 每次断开连接的时候,需要清除缓存。
    gatt.disconnect();
    gatt.close();
    gatt = null;
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号