鸿蒙BLE蓝牙通信开发总结 原创 精华
目标
通过BLE扫描和广播提供的开放能力,可以根据指定状态获取外围设备、启动或停止BLE扫描、广播、数据交互。
关于BLE蓝牙的扫描和广播你可以查看官方文档
效果
蓝牙介绍
蓝牙是短距离无线通信的一种方式,支持蓝牙的两个设备必须配对后才能通信。HarmonyOS蓝牙主要分为传统蓝牙和低功耗蓝牙(通常称为BLE,Bluetooth Low Energy)。传统蓝牙指的是蓝牙版本3.0以下的蓝牙,低功耗蓝牙指的是蓝牙版本4.0以上的蓝牙。
如果你对蓝牙感兴趣,可以看看 HarmonyOS 蓝牙介绍或者我前面写的一篇文章:鸿蒙关于蓝牙的那些事
概念
在进入实战之前,先说明一个BLE蓝牙的通信协议,GATT【Generic Attribute Profile】,GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短的数据段被称为属性(Attribute)。在说明GATT之前还需要知道一个GAP【Generic Access Profile】。
GAP包含:搜索蓝牙设备(Discovery)、管理连接(Link establishment),还有不同的安全等级(Security)。以及从用户层面访问一些参数的方式。GAP给设备定义了若干角色,其中主要的两个是:外围设备(Peripheral)和中心设备(Central)。
- 外围设备:这一般就是非常小或者简单的低功耗设备,用来提供数据,并连接到一个更加相对强大的中心设备,例如:蓝牙手环。
- 中心设备:中心设备相对比较强大,用来连接其他外围设备,例如手机。
GATT定义两个BLE设备通过叫做Service和Characteristic的东西进行通信,他使用了ATT(Attribute Protocol)协议,需要说明的是,GATT连接必需先经过GAP协议。
另外,特别注意的是:GATT连接是独占的。也就是一个BLE外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就对其他设备不可见了。当设备断开,它又开始广播。中心设备和外设需要双向通信的话,唯一的方式就是建立GATT连接。
GATT连接的网络拓扑
一个外设只能连接一个中心设备,而一个中心设备可以连接多个外设。中心设备负责扫描外围设备、发现广播。外围设备负责发送广播。
前置条件
一、前期准备
说明:如果需要完成蓝牙间的通信则需要借助蓝牙中的服务,如何获取BLE蓝牙相关的MAC地址和服务编号【uuid】可以参看我前面写的一篇文章:鸿蒙关于蓝牙的那些事
1.1、获取外围蓝牙设备的MAC
本此讲解的实战中使用到的相关设备MAC
- MAC:E2:xx:xx:xx:xx:EB
1.2、获取服务编号【uuid】
本此讲解的实战中使用到的相关设备UUID
- Service:6e40xxxx-xxxx-xxxx-e0a9-e50e24dcca9e
- Notify:6e40xxxx-xxxx-xxxx-e0a9-e50e24dcca9e
业务逻辑梳理
- 权限问题,首先需要注册蓝牙相关权限;
- 搜索蓝牙,应用启动后可以手动的开启和关闭蓝牙扫描;
- 连接蓝牙,根据蓝牙的mac地址,调用connect进行连接;
- 遍历蓝牙特征,在蓝牙连接成功后,获取蓝牙的服务特征,设置指定GATT特征通知;
- 通知数据,将数据通过蓝牙服务中的通知属性发送;
- 接受通知,中心设备通过characteristicChangedEvent接收通知数据,并显示在屏幕上;
- 关闭蓝牙,在应用推出后,需要释放资源,断开连接。
实战:BLE蓝牙设备间的数据交互–中心设备接收外围设备的通知数据
一、创建项目
说明:通过DevEco Studio创建Application项目(java)。
二、权限
2.1、声明权限
说明:在项目的config.json中声明操作蓝牙必要的权限。
- ohos.permission.USE_BLUETOOTH:允许应用查看蓝牙的配置。
- ohos.permission.DISCOVER_BLUETOOTH:允许应用配置本地蓝牙,并允许其查找远端设备且与之配对连接。
- ohos.permission.LOCATION:允许应用在前台运行时获取位置信息。
代码如下:
2.2、显式声明敏感权限
说明:ohos.permission.LOCATION属于敏感权限,需要在代码中显式声明。在MainAbility中动态申请权限,代码如下:
三、启动蓝牙
说明:如果蓝牙处于关闭状态,请求将设备的蓝牙开启,代码如下:
四、中心设备进行BLE扫描
4.1、API说明
4.1.1、BLE中心设备管理类:BleCentralManager
接口名 | 功能描述 |
---|---|
startScan(List<BleScanFilter> filters) | 进行BLE蓝牙扫描,并使用filters对结果进行过滤。 |
stopScan() | 停止BLE蓝牙扫描。 |
getDevicesByStates(int[] states) | 根据状态获取连接的外围设备。 |
BleCentralManager(Context context, BleCentralManagerCallback callback) | 获取中心设备管理对象。 |
4.1.2、中心设备管理回调类:BleCentralManagerCallback
接口名 | 功能描述 |
---|---|
scanResultEvent(BleScanResult result) | 扫描到BLE设备的结果回调 |
groupScanResultsEvent(List<BleScanResult> scanResults) | 扫描到一组BLE设备的结果回调 |
scanFailedEvent(int resultCode) | 启动扫描失败的回调。 |
4.2、扫描回调的处理
BLE扫描之前要先实现扫描回调:BleCentralManagerCallback的接口,在scanResultEvent回调中可以获取你需要的外围设备实例,代码如下:
4.3、获取中心设备管理对象
调用BleCentralManager(BleCentralManagerCallback callback)接口获取中心设备管理对象。代码如下:
4.4、启动扫描
调用startScan()开始扫描BLE设备,在回调【BleCentralManagerCallback】中获取扫描到的BLE设备。
值得一提的是,启动扫描接口中,可以传入蓝牙扫描过滤器【BleScanFilter】,如果过滤器为空,则不过滤。
下面使用指定的MAC地址进行过滤启动蓝牙扫描,代码如下:
五、蓝牙连接
5.1、API
5.1.1、BLE蓝牙外围设备操作类:BlePeripheralDevice相关接口说明
接口名称 | 功能描述 |
---|---|
connect(boolean isAutoConnect, BlePeripheraCallback callback) | 重新连接GATT外围设备,isAutoConnect表示是否自动进行连接。 |
iscoverServices() | 搜索外围设备支持的服务,特征和描述。 |
getServices() | 获取外围设备支持的所有GATT服务。 |
getService(UUID uuid) | 根据UUID获取外围设备支持的某个GATT服务。 |
disconnect() | 与外围设备断开BLE连接。 |
close() | 关闭蓝牙GATT客户端。 |
readCharacteristic(GattCharacteristic characteristic) | 读取外围设备GATT特征。 |
writeCharacteristic(GattCharacteristic characteristic) | 写指定外围设备的GATT特征值。 |
setNotifyCharacteristic(GattCharacteristic characteristic, boolean enable) | 设置指定GATT特征通知的使能/去使能。 |
readDescriptor (GattDescriptor descriptor) | 读取外围设备GATT描述值。 |
writeDescriptor(GattDescriptor descriptor) | 写指定外围设备的GATT描述值。 |
readRemoteRssiValue() | 读取已连接外围设备的RSSI。 |
requestBleConnectionPriority(int connPriority) | 请求链接参数更新。 |
requestBleMtuSize(int mtu) | 请求用于给定连接的MTU大小。 |
5.1.2、BLE蓝牙外围设备操作回调类:BlePeripheralCallback相关接口说明
接口名称 | 功能描述 |
---|---|
servicesDiscoveredEvent(int status) | 外围设备服务发生更新触发的回调。 |
connectionStateChangedEvent(int connectionState) | 外围设备GATT连接状态发生变化时的回调。 |
characteristicReadEvent(GattCharacteristic characteristic, int ret) | GATT特征值读操作回调。 |
characteristicWriteEvent(GattCharacteristic characteristic, int ret) | GATT特征值写操作回调。 |
characteristicChangedEvent(GattCharacteristic characteristic) | 外围设备特征通知触发的回调。 |
descriptorReadEvent(GattDescriptor descriptor, int ret) | GATT描述值读操作回调。 |
descriptorWriteEvent(GattDescriptor descriptor, int ret) | GATT描述值写操作回调。 |
readRemoteRssiEvent(int rssi, int ret) | 外围设备发来读取RSSI的回调。 |
tuUpdateEvent(int mtu, int ret) | GATT设备链接的MTU变化通知的回调。 |
5.2、实现外围设备操作回调:BlePeripheralCallback,部分代码如下:
在回调的接口中可以做三件事。
1、在connectionStateChangeEvent回调接口中,如果GATT连接成功,则可以调用mPeripheralDevice.discoverServices()获取外围设备支持的 Services、Characteristics 等特征值,在回调 servicesDiscoveredEvent(int status) 中获取外围设备支持的服务和特征值,并根据 UUID 判断是什么服务。代码如下:
2、在servicesDiscoveredEvent回调接口中,如果Service获取成功,则根据获取到的服务和特征值,调用 setNotifyCharacteristic设置指定GATT特征通知。代码如下:
3、在characteristicChangedEvent回调接口中处理外围设备特征的通知,可以从中获取到通知的数据。代码如下:
5.3、设备蓝牙连接
说明:中心设备与外围设备建立连接,调用connect(boolean isAutoConnect, BlePeripheraCallback callback)建立与外围BLE设备的GATT连接,boolean参数isAutoConnect用于设置是否允许设备在可发现距离内自动建立GATT连接。代码如下:
六、常量
说明:Constant是用于定义常量类,其中定义了业务中需要使用的常量。其中"X"需要替换成你的蓝牙设备信息。
到目前为止,就完成了中心设备与外围设备的连接和相关的监听回调,当外围设备通过NOTIFY_CHARACTER_UUID发送的通知在外围设备操作回调接口characteristicChangedEvent中就能监听到变更,在参数GattCharacteristic中就可以获取到通知中的数据内容。
七、代码
7.1、BLE蓝牙中心设备的完整代码
感谢
如果您能看到最后,还希望您能动动手指点个赞,一个人能走多远关键在于与谁同行,我用跨越山海的一路相伴,希望得到您的点赞。
前排点赞
您好,请问有完整代码文件吗
java已经落伍了,js的安排一下呗
最近正在写
基于OpenHarmony 3.2 beta版本的BLE蓝牙操作实战:https://ost.51cto.com/posts/19301
大佬你好,请问发现服务后回调中,通过判断设置提醒成功了,但是没有回调。我看了安卓开发的贴,如下图,然后就调用getPermissions判断一下,值为0。这个情况怎么解决啊。
问题已解决,在设置完setNotifyCharacteristic后,加入以下代码:
可以看看这个:ble开发setNotifyCharacteristic后无法获得characteristicChangedEvent回调-华为开发者论坛 | 华为开发者联盟 (huawei.com)
请问大佬:按此代码完成后,无法扫描到外围设备,什么原因啊?我的手机是华为P40,外围BLE是原子的蓝牙模块,P40目前运行的是鸿蒙最新版本。
代码编译的最低版本是SDK4,最高是SDK6,其他权限配置也是按照大佬的写的。
好像中心设备回调函数没有起作用...
你可以先用蓝牙调试工具确认下周边的蓝牙是否能正常发现。
啥时候华为开放星闪技术和芯片,让我们这些爱好者接触更好的技术。楼主写得很棒,谢谢!
有的代码也有同样问题,请问解决了吗