各位同学,掌声欢迎来到今天的“Web Bluetooth API:让你的网页和智能穿戴设备谈恋爱”讲座! 我是你们的老朋友,今天咱们就来聊聊如何用几行代码,让你的网页直接和智能手表、手环、甚至智能体重秤眉来眼去。
开场白:蓝牙,不再是遥远的传说
以前,网页想和蓝牙设备打交道?那简直比登天还难!你得写 Native 应用,用各种复杂的 SDK,费时费力。但 Web Bluetooth API 的出现,就像一道闪电,劈开了这片混沌,让一切变得简单起来。现在,只需要你的浏览器支持(Chrome、Edge、Opera 等主流浏览器),你就能在网页里直接控制蓝牙设备,是不是想想都觉得刺激?
Web Bluetooth API 的核心概念
Web Bluetooth API 主要围绕着以下几个核心概念展开:
navigator.bluetooth.requestDevice()
: 这是整个 API 的入口,负责弹出一个设备选择窗口,让用户选择要连接的蓝牙设备。BluetoothDevice
: 代表一个蓝牙设备,包含了设备的信息(例如名称、UUID 等)和连接状态。BluetoothGATTServer
: GATT(Generic Attribute Profile)服务器,负责提供设备的各种服务和特性。BluetoothGATTService
: GATT 服务,是对设备功能的抽象,例如心率监测、电池电量等。BluetoothGATTCharacteristic
: GATT 特性,是服务的具体属性,例如心率值、电池电量值等。
简单来说,你可以把蓝牙设备想象成一栋大楼,BluetoothGATTServer
是大楼的管理员,BluetoothGATTService
是大楼里的不同房间(比如健身房、餐厅),BluetoothGATTCharacteristic
则是房间里的具体物品(比如跑步机、餐桌)。
实战演练:连接你的心率带
光说不练假把式,咱们直接上代码,以连接一个心率带为例,一步步探索 Web Bluetooth API 的奥秘。
1. 启动设备选择器
首先,我们需要调用 navigator.bluetooth.requestDevice()
,让浏览器弹出设备选择窗口。这个函数接收一个 filters
参数,用于指定要搜索的设备类型。
async function connectHeartRateSensor() {
try {
const device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }] // 指定只搜索心率服务
});
console.log('设备名称:' + device.name);
console.log('设备 ID:' + device.id);
// 连接 GATT 服务器
await connectGattServer(device);
} catch (error) {
console.log('连接失败:' + error);
}
}
这段代码会弹出一个窗口,列出所有提供 "heart_rate" 服务的蓝牙设备。用户选择设备后,requestDevice()
函数会返回一个 BluetoothDevice
对象。
小贴士:filters
参数的妙用
filters
参数非常强大,你可以用它来精确控制要搜索的设备类型。除了指定服务 UUID,还可以指定设备名称或名称前缀。
参数 | 描述 | 示例 |
---|---|---|
services |
一个包含 GATT 服务 UUID 的数组。只搜索提供这些服务的设备。 | [{ services: ['heart_rate', 'battery_service'] }] |
name |
设备名称。只搜索名称完全匹配的设备。 | [{ name: 'MyHeartRateSensor' }] |
namePrefix |
设备名称前缀。只搜索名称以此前缀开头的设备。 | [{ namePrefix: 'HRM-' }] |
deviceId |
蓝牙设备的device ID。 | [{ deviceId: '39c50141-1057-456f-a0f4-a822349f744a' }] |
manufacturerData |
制造商数据。如果设备广播中包含了特定的制造商数据,你可以使用此过滤器。 | [{ manufacturerData: [{ companyIdentifier: 0x004C /* Apple's Company Identifier */ }] }] |
2. 连接 GATT 服务器
拿到 BluetoothDevice
对象后,下一步是连接它的 GATT 服务器。
async function connectGattServer(device) {
try {
const server = await device.gatt.connect();
console.log('GATT 服务器已连接');
// 获取心率服务
await getHeartRateService(server);
} catch (error) {
console.log('GATT 连接失败:' + error);
}
}
device.gatt.connect()
返回一个 BluetoothGATTServer
对象,代表设备的 GATT 服务器。
注意:gatt.connect()
的玄机
gatt.connect()
是一个异步操作,如果设备已经连接,它会立即返回;如果设备未连接,它会尝试建立连接。
3. 获取心率服务
连接 GATT 服务器后,我们需要获取心率服务,才能读取心率数据。
async function getHeartRateService(server) {
try {
const service = await server.getPrimaryService('heart_rate');
console.log('心率服务已获取');
// 获取心率测量特性
await getHeartRateMeasurementCharacteristic(service);
} catch (error) {
console.log('获取心率服务失败:' + error);
}
}
server.getPrimaryService('heart_rate')
返回一个 BluetoothGATTService
对象,代表心率服务。
服务 UUID 的重要性
每个 GATT 服务都有一个唯一的 UUID(Universally Unique Identifier),用于标识服务的类型。心率服务的 UUID 是 "heart_rate"。
4. 获取心率测量特性
获取心率服务后,我们需要获取心率测量特性,才能读取心率数据。
async function getHeartRateMeasurementCharacteristic(service) {
try {
const characteristic = await service.getCharacteristic('heart_rate_measurement');
console.log('心率测量特性已获取');
// 启动心率数据通知
await startHeartRateNotifications(characteristic);
} catch (error) {
console.log('获取心率测量特性失败:' + error);
}
}
service.getCharacteristic('heart_rate_measurement')
返回一个 BluetoothGATTCharacteristic
对象,代表心率测量特性。
特性 UUID 的重要性
每个 GATT 特性也有一个唯一的 UUID,用于标识特性的类型。心率测量特性的 UUID 是 "heart_rate_measurement"。
5. 启动心率数据通知
获取心率测量特性后,我们需要启动数据通知,才能实时接收心率数据。
async function startHeartRateNotifications(characteristic) {
try {
await characteristic.startNotifications();
console.log('心率数据通知已启动');
// 监听心率数据变化事件
characteristic.addEventListener('characteristicvaluechanged', handleHeartRateData);
} catch (error) {
console.log('启动心率数据通知失败:' + error);
}
}
characteristic.startNotifications()
启动数据通知。当心率数据发生变化时,characteristicvaluechanged
事件会被触发。
6. 处理心率数据
最后,我们需要编写 handleHeartRateData
函数,处理接收到的心率数据。
function handleHeartRateData(event) {
const value = event.target.value;
const heartRate = value.getUint8(1); // 获取心率值
console.log('心率:' + heartRate + ' bpm');
// 将心率值显示在网页上
document.getElementById('heartRate').textContent = heartRate;
}
event.target.value
是一个 DataView
对象,包含了心率数据的原始字节。我们需要根据数据的格式,从 DataView
对象中提取心率值。
完整代码示例
<!DOCTYPE html>
<html>
<head>
<title>Web Bluetooth 心率监测</title>
</head>
<body>
<h1>心率:<span id="heartRate">--</span> bpm</h1>
<button onclick="connectHeartRateSensor()">连接心率带</button>
<script>
async function connectHeartRateSensor() {
try {
const device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }]
});
console.log('设备名称:' + device.name);
console.log('设备 ID:' + device.id);
const server = await device.gatt.connect();
console.log('GATT 服务器已连接');
const service = await server.getPrimaryService('heart_rate');
console.log('心率服务已获取');
const characteristic = await service.getCharacteristic('heart_rate_measurement');
console.log('心率测量特性已获取');
await characteristic.startNotifications();
console.log('心率数据通知已启动');
characteristic.addEventListener('characteristicvaluechanged', handleHeartRateData);
} catch (error) {
console.log('连接失败:' + error);
}
}
function handleHeartRateData(event) {
const value = event.target.value;
const heartRate = value.getUint8(1); // 获取心率值
console.log('心率:' + heartRate + ' bpm');
document.getElementById('heartRate').textContent = heartRate;
}
</script>
</body>
</html>
将这段代码保存为 HTML 文件,然后在支持 Web Bluetooth API 的浏览器中打开,点击“连接心率带”按钮,就可以连接你的心率带,并在网页上实时显示心率数据了。
进阶技巧:读取和写入数据
除了监听数据通知,Web Bluetooth API 还支持读取和写入数据。
- 读取数据: 使用
characteristic.readValue()
函数可以读取特性的当前值。 - 写入数据: 使用
characteristic.writeValue()
函数可以向特性写入新的值。
示例:读取电池电量
假设你的设备提供了一个电池服务,你可以使用以下代码读取电池电量:
async function getBatteryLevel(service) {
try {
const characteristic = await service.getCharacteristic('battery_level');
const value = await characteristic.readValue();
const batteryLevel = value.getUint8(0); // 获取电池电量值
console.log('电池电量:' + batteryLevel + '%');
} catch (error) {
console.log('获取电池电量失败:' + error);
}
}
示例:写入数据
假设你的设备提供了一个控制 LED 灯的服务,你可以使用以下代码控制 LED 灯的开关:
async function setLedState(characteristic, state) {
try {
const value = new Uint8Array([state]); // 1 表示开,0 表示关
await characteristic.writeValue(value);
console.log('LED 灯状态已设置');
} catch (error) {
console.log('设置 LED 灯状态失败:' + error);
}
}
安全性 considerations
Web Bluetooth API 涉及用户隐私和安全,因此浏览器对 API 的使用做了一些限制:
- HTTPS Only: Web Bluetooth API 只能在 HTTPS 协议下使用,确保数据传输的安全性。
- User Gesture Required: 启动设备扫描必须由用户主动触发(例如点击按钮),防止恶意网站未经用户允许扫描蓝牙设备。
- Permissions: 浏览器会询问用户是否允许网站访问蓝牙设备,用户可以随时撤销权限。
Web Bluetooth API 的应用场景
Web Bluetooth API 的应用场景非常广泛,例如:
- 智能穿戴设备: 监测心率、步数、睡眠质量等数据。
- 智能家居: 控制灯泡、插座、窗帘等设备。
- 医疗健康: 远程监测血糖、血压等数据。
- 工业自动化: 控制机器人、传感器等设备。
- 教育: 开发互动式教学工具。
Web Bluetooth API 的优势
- 跨平台: 可以在支持 Web Bluetooth API 的任何浏览器中使用,无需针对不同平台开发不同的应用。
- 易于开发: 使用 JavaScript 编写,学习成本低,开发效率高。
- 安全可靠: 受浏览器安全机制保护,用户可以控制网站对蓝牙设备的访问权限。
- 无需安装: 用户只需打开网页即可使用,无需安装任何插件或应用。
Web Bluetooth API 的局限性
- 浏览器支持: 并非所有浏览器都支持 Web Bluetooth API。
- 设备兼容性: 并非所有蓝牙设备都支持 Web Bluetooth API。
- 安全性限制: 受浏览器安全机制的限制,无法访问某些底层蓝牙功能。
总结:拥抱 Web Bluetooth API 的未来
Web Bluetooth API 是一个强大而灵活的工具,它为 Web 应用打开了通往蓝牙世界的大门。虽然目前还存在一些局限性,但随着浏览器支持的不断完善和蓝牙技术的不断发展,Web Bluetooth API 的应用前景将更加广阔。
希望今天的讲座能帮助大家更好地理解和使用 Web Bluetooth API。下次有机会,咱们再一起探索更多有趣的 Web 技术!