之前公司想做一个应用,需要用到蓝牙,当时没有做深入的调研,就直接否定了在h5上做的想法。
今天刷到了这篇帖子,学习整理一下。
虽然当前网络蓝牙 API 规范还没有最终确定,但是已经得到了广泛的支持。比如ChromeOS,安卓6以后的安卓版chrome浏览器,,Mac上Chrome56及之后的版本,windows10上Chrome70及之后的版本。
之前在小程序,app上通过蓝牙能做的事,以后也能通过h5实现了。比如连接蓝牙,向蓝牙发送一个请求,接收来自蓝牙的广播,读写蓝牙数据,监听蓝牙连接和断开,读写蓝牙描述符等。
使用要求
只能在https状态下使用
为了数据传输安全,h5上的蓝牙模块,只支持在https的状态下使用,http不能用。但是本地使用没有限制,可以使用localhost调试。需要用户手动触发和蓝牙的连接行为
同样是为了安全考虑,拒绝使用程序直接连接蓝牙。必须经过用户操作,比如经过点击,触摸等事件来触发蓝牙连接。
js连接蓝牙实战
寻找蓝牙设备
寻找指定蓝牙设备
现有的浏览器蓝牙连接,支持蓝牙4.0及之后的版本。通过调用navigator.bluetooth.requestDevice
函数向用户申请蓝牙权限,浏览器会弹出一个有蓝牙列表的弹框供用户选择连接。
navigator.bluetooth.requestDevice
可以通过传一个有filters参数的对象,来获取请求获取蓝牙权限并且配对。例子:
1 | navigator.bluetooth.requestDevice({filters: [ |
filters
数组中可以传入一个或者多个对象,这些对象的字段包括:
name
蓝牙名称,可以通过自己的手机或者电脑蓝牙列表看到。namePrefix
蓝牙名称的开头部分, 比如蓝牙全程叫’ABCD’,可以放入’A’或者’AB’services
是一个数组,里面用来放置蓝牙的服务名称,如果不知道名称,可以放置服务完整UUID或者16或者32比特的UUID。如果不知道的可以在这里查询,或者点击这里直接查看。manufacturerData
根据供应商数据选择蓝牙设备,是一个数组。
注意,如果filters用的是services以外的字段,需要另外一个和filters平级的字段optionalServices来加入需要的服务名称。在实际开发中,我们可能比较难知道自己的蓝牙设备是什么服务,所以还不如一开始就用services。用service字段时可以先用其它设备获取当前这批蓝牙的service id,然后开始在h5中集成。也许未来这个接口会改吧,现在这样太不方便了。
如果想寻找周围所有的蓝牙设备,然后再从设备中去过滤,可以不传入filters
,而是传入布尔值acceptAllDevices
,并且设置为true,这样就能搜索到所有的蓝牙设备供匹配,如下:
1 | navigator.bluetooth.requestDevice({ |
连接蓝牙设备
找到蓝牙设备,并且配对成功后,接下来就是要连接蓝牙设备了。在配对成功的回掉函数中,我们将返回的结果打印出来,可以看到如下数据结构:
可以看到,返回的对象中有一个gatt
对象,它的原型链上有一堆的方法,其中一个就是connect
,里面还有一个参数叫connected
,用来表示是否已经连接了蓝牙,如果已经连接了,我们可以对应的做一下策略。接下来我们开始连接,在接下来的连接中,为了代码结构清晰一点,将使用await/async
。
1 | let device = '' |
断开蓝牙设备
前面我们连接蓝牙设备,后面可能还需要断开蓝牙设备。在配对蓝牙设备的截图中,可以看到有一个disconnect
,接下来我们用它来断开蓝牙。
1 | async function disconnectBluetooth () { |
获取取蓝牙的服务和特征码
在连接上蓝牙后,我们就可以开始获取蓝牙的服务和特征码。
- 获取服务
1 | let service = await server.getPrimaryService('6e400001-b5a3-f393-e0a9-e50e24dcca9e') |
从这里开始的数据,都是我根据文档所写,因为我发获取自己设备的服务名称,无法继续在自己手上的蓝牙测试下去。
- 获取特征码
1 | let characteristic = await service.getCharacteristic('battery_level') |
向蓝牙写入数据
获取到characteristic
后,就可以直接用它的writeValue
方法写入数据了。如下:
1 | characteristic.writeValue(data) |
接收来自蓝牙的数据
获取到characteristic
后,可以为它增加一个监听函数,监听来自蓝牙的数据1
2
3characteristic.addEventListener('characteristicvaluechanged',(data) => {
console.log(data)
});
js直接拦截蓝牙用起来挺顺畅,但是不知道服务名这一点确实让人头疼