Android低功耗蓝牙使用介绍

最近在项目中需要实现一个蓝牙摇一摇开门的功能,蓝牙和门口机数据交互的协议已经给定,考虑到蓝牙的适配性,决定使用低功耗蓝牙进行开发。低功耗蓝牙是Android 4.3开始支持的,其主要特点是主要特点是快速搜索,快速连接,超低功耗保持连接和数据传输,常被用在可穿戴设备中。

1. 开发之前的准备工作

在进行BLE(Bluetooth Low Energy)开发之前,我们先来了解一波BLE数据传输涉及到的关键概念:

Generic Attribute Profile (GATT)

通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。

Attribute Protocol (ATT)

GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。
每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。

Characteristic

Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。

Descriptor

对Characteristic的描述,例如范围、计量单位等。

Service

Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,
它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。

2. 开发需要的权限

Android使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限,如果Android版本在5.0以上,蓝牙还需要位置权限。

1.png

3. 蓝牙的开启和蓝牙状态的监听

在蓝牙编程中,首先我们要知道如何去开启和关闭蓝牙,下面介绍两种方法:

1) 通过获取蓝牙管理服务和适配器来开启、关闭蓝牙,获取当前蓝牙是否为可用状态;

2.png

2) 跳转到系统蓝牙设置界面,由用户自行开启蓝牙,并通过广播监听蓝牙开启与关闭的通知,通过蓝牙适配器来获取当前蓝牙是否为可用状态:

跳转蓝牙设置界面

3.png

注册蓝牙状态广播监听

4.png

蓝牙广播监听,可以接受蓝牙开启,关闭时的通知:

5.png

蓝牙是否开启的判断

6.png

第一种方法可以用来直接开关蓝牙,如果是Android 6.0系统及以上的还需要添加动态申请权限代码;第二种方法是引导用户进入设置界面进行手动设置,再通过监听开关状态来执行后续操作,不需要动态申请权限;

4. 蓝牙设备的扫描和连接

1)启动蓝牙后,我们就要开始使用蓝牙进行扫描,发现我们想要连接的设备。在Android5.0版本时,Google对BLE更新了API,添加了新的扫描方法和回调,在下面代码中会进行区分:

mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

开始扫描

if(Build.VERSION.SDK_INT >= 21){
   mBluetoothLeScanner.startScan(mScanCallback);
}else{
  mBluetoothAdapter.startLeScan(mLeScanCallback);
}

关闭扫描

if(Build.VERSION.SDK_INT >= 21){
   mBluetoothLeScanner.stopScan(mScanCallback);
}else{
  mBluetoothAdapter.stopLeScan(mLeScanCallback);
}

扫描回调也不相同

7.png

2) 扫描找到想要连接的设备后,就可以开始进行设备连接了:

8.png

注意:根据需要决定是否对有连接过的设备进行重新连接。比如有些设备在连接通讯后就自行断开,连接总时长只有几秒钟的,这样的不需要保留地址,每次都直接连接比较好。

连接设备时,会触发一个通信的回调,这个回调比较重要,在设备连接,数据通信中都会用到:

9.png

在连接状态回调中判断连接状态,连接成功后,调用gatt.discoverServices()方法去发现连接的设备提供的服务及其特征和描述符;发现成功后,会调用onServicesDiscovered()回调,表示可以与之通信了;

10.png

发现服务后,通过handler回调到主线程,执行了下面的方法用来设置后续需要用到连接的服务节点下的Characteristic发生改变时进行通知:

11.png

此处是获取了开门服务,设置开门服务下接受到命令返回的Characteristic

12.png

setCharacteristicNotification()方法会触发onCharacteristicChanged()回调。接受到onCharacteristicChanged()回调后证明可以设置通知成功,可以开始发送通讯指令了。

13.png

5. 蓝牙的数据发送和接收

经过4中的步骤后,此时远程设备已经准备好进行蓝牙通讯了,下面开始发送指令:

14.png

此处是向开门服务下的接收命令的BluetoothGattCharacteristic对象写入命令数据。

15.png

writeCharacteristic()方法会触发onCharacteristicWrite()回调

16.png

注意:BLE向设备写入数据时,最大20byte,如果需要写入的数据大于20byte,可以选择将数据进行分割,先发送前20byte,利用回调触发将后续数据依次发送,每次最多20byte。

远程设备接收到完整指令并执行后,特征值变化会触发onCharacteristicChanged()回调,并传回数据

17.png

这样,一个完整的通信循环就完成了。

6. 总结

蓝牙BLE本身的流程并不复杂,关键在于存在有许多特殊情况需要处理,下面对特殊情况的处理进行叙述和总结:

1、 调用gatt.discoverServices()方法后不执行onServiceDiscovered()回调,这种问题有两种情况,一种是设备距离远,回调时间过长,一种是并没有真正连接到设备,可以尝试将gatt.discoverServices()方法放到主线程中执行;

2、 onServicesDiscovered 回调里不能直接执行 write /readDataFromCharacteristic() 或者 enableNotificationOfCharacteristic之类的,而要放到主线程里执行,可以使用 handler转换线程;

3、 扫描尽量不要放在主线程进行,可以放入子线程中,部分机型会出现do too many work in main thread。

4、 任何出错,超时,用完就马上调用Gatt.disconnect(), Gatt.close()。

你可能感兴趣的:(Android低功耗蓝牙使用介绍)