Android BLE蓝牙开发详解
Android BLE蓝牙开发详解
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的错误。
- 频繁连接设备:在断开连接的时候给一个缓冲时间,并且清除缓存
- 每次断开连接的时候,需要清除缓存。
gatt.disconnect();
gatt.close();
gatt = null;