Web Bluetooth API cho phép các trang web giao tiếp với thiết bị Bluetooth.
Nếu tôi nói rằng các trang web có thể giao tiếp với các thiết bị Bluetooth ở gần theo cách bảo đảm quyền riêng tư và an toàn thì sao? Nhờ đó, thiết bị theo dõi nhịp tim, bóng đèn hát và thậm chí cả rùa đều có thể tương tác trực tiếp với một trang web.
Cho đến nay, chỉ những ứng dụng dành riêng cho nền tảng mới có thể tương tác với các thiết bị Bluetooth. Web Bluetooth API hướng đến việc thay đổi điều này và mang nó đến các trình duyệt web.
Trước khi bắt đầu
Tài liệu này giả định rằng bạn có một số kiến thức cơ bản về cách hoạt động của Bluetooth năng lượng thấp (BLE) và Hồ sơ thuộc tính chung.
Mặc dù quy cách Web Bluetooth API chưa hoàn thiện, nhưng các tác giả quy cách đang tích cực tìm kiếm những nhà phát triển nhiệt tình để dùng thử API này và đưa ra ý kiến phản hồi về quy cách cũng như ý kiến phản hồi về việc triển khai.
Một phần của Web Bluetooth API có trong ChromeOS, Chrome cho Android 6.0, Mac (Chrome 56) và Windows 10 (Chrome 70). Điều này có nghĩa là bạn có thể yêu cầu và kết nối với các thiết bị Bluetooth năng lượng thấp ở gần, đọc/ghi các đặc điểm của Bluetooth, nhận Thông báo GATT, biết thời điểm thiết bị Bluetooth bị ngắt kết nối, và thậm chí đọc và ghi vào các bộ mô tả Bluetooth. Hãy xem bảng Khả năng tương thích của trình duyệt của MDN để biết thêm thông tin.
Đối với Linux và các phiên bản Windows cũ hơn, hãy bật cờ #experimental-web-platform-features trong about://flags.
Có sẵn cho bản dùng thử theo nguyên gốc
Để thu thập càng nhiều ý kiến phản hồi càng tốt từ các nhà phát triển sử dụng Web Bluetooth API, trước đây Chrome đã thêm tính năng này vào Chrome 53 dưới dạng một thử nghiệm theo nguyên gốc cho ChromeOS, Android và Mac.
Giai đoạn dùng thử đã kết thúc thành công vào tháng 1 năm 2017.
Yêu cầu về bảo mật
Để hiểu rõ những điểm đánh đổi về bảo mật, bạn nên xem bài đăng Mô hình bảo mật Web Bluetooth của Jeffrey Yasskin, một kỹ sư phần mềm trong nhóm Chrome, đang làm việc về quy cách Web Bluetooth API.
Chỉ HTTPS
Vì API thử nghiệm này là một tính năng mới mạnh mẽ được thêm vào web, nên API này chỉ được cung cấp cho các bối cảnh an toàn. Điều này có nghĩa là bạn cần tạo bằng TLS.
Bắt buộc phải có cử chỉ của người dùng
Là một tính năng bảo mật, việc phát hiện các thiết bị Bluetooth bằng navigator.bluetooth.requestDevice phải được kích hoạt bằng một cử chỉ của người dùng, chẳng hạn như thao tác chạm hoặc nhấp chuột. Chúng ta đang nói về việc theo dõi các sự kiện pointerup, click và touchend.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
Tìm hiểu về mã
API Web Bluetooth phụ thuộc nhiều vào Promise của JavaScript. Nếu bạn chưa quen với các đối tượng này, hãy xem hướng dẫn tuyệt vời này về Lời hứa. Một điều nữa là () => {} là Hàm mũi tên ECMAScript 2015.
Yêu cầu thiết bị Bluetooth
Phiên bản này của quy cách Web Bluetooth API cho phép các trang web (chạy ở vai trò Trung tâm) kết nối với các Máy chủ GATT từ xa qua một kết nối BLE. Công nghệ này hỗ trợ giao tiếp giữa các thiết bị triển khai Bluetooth 4.0 trở lên.
Khi một trang web yêu cầu quyền truy cập vào các thiết bị lân cận bằng cách sử dụng navigator.bluetooth.requestDevice, trình duyệt sẽ nhắc người dùng bằng một bộ chọn thiết bị để họ có thể chọn một thiết bị hoặc huỷ yêu cầu.
Hàm navigator.bluetooth.requestDevice() nhận một đối tượng bắt buộc xác định các bộ lọc. Các bộ lọc này chỉ trả về những thiết bị khớp với một số dịch vụ GATT Bluetooth được quảng cáo và/hoặc tên thiết bị.
Bộ lọc dịch vụ
Ví dụ: để yêu cầu các thiết bị Bluetooth quảng cáo Dịch vụ pin GATT Bluetooth:
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Tuy nhiên, nếu Dịch vụ GATT Bluetooth của bạn không có trong danh sách các dịch vụ GATT Bluetooth được tiêu chuẩn hoá, thì bạn có thể cung cấp UUID Bluetooth đầy đủ hoặc một dạng ngắn 16 hoặc 32 bit.
navigator.bluetooth.requestDevice({
filters: [{
services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
}]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Bộ lọc tên
Bạn cũng có thể yêu cầu các thiết bị Bluetooth dựa trên tên thiết bị được quảng cáo bằng khoá bộ lọc name hoặc thậm chí là tiền tố của tên này bằng khoá bộ lọc namePrefix. Xin lưu ý rằng trong trường hợp này, bạn cũng cần xác định khoá optionalServices để có thể truy cập vào mọi dịch vụ không có trong bộ lọc dịch vụ. Nếu không, bạn sẽ gặp lỗi sau này khi cố gắng truy cập vào các tệp đó.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Bộ lọc dữ liệu của nhà sản xuất
Bạn cũng có thể yêu cầu các thiết bị Bluetooth dựa trên dữ liệu dành riêng cho nhà sản xuất được quảng cáo bằng khoá bộ lọc manufacturerData. Khoá này là một mảng gồm các đối tượng có khoá Giá trị nhận dạng công ty Bluetooth bắt buộc có tên là companyIdentifier. Bạn cũng có thể cung cấp tiền tố dữ liệu để lọc dữ liệu của nhà sản xuất từ các thiết bị Bluetooth bắt đầu bằng tiền tố đó. Xin lưu ý rằng bạn cũng cần xác định khoá optionalServices để có thể truy cập vào mọi dịch vụ không có trong bộ lọc dịch vụ. Nếu không, sau này bạn sẽ gặp lỗi khi cố gắng truy cập vào các tệp đó.
// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: [{
companyIdentifier: 0x00e0,
dataPrefix: new Uint8Array([0x01, 0x02])
}]
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Bạn cũng có thể sử dụng mặt nạ với tiền tố dữ liệu để so khớp một số mẫu trong dữ liệu của nhà sản xuất. Hãy xem video giải thích về bộ lọc dữ liệu Bluetooth để tìm hiểu thêm.
Bộ lọc loại trừ
Lựa chọn exclusionFilters trong navigator.bluetooth.requestDevice() cho phép bạn loại trừ một số thiết bị khỏi trình chọn trình duyệt. Bạn có thể dùng bộ lọc này để loại trừ những thiết bị phù hợp với một bộ lọc rộng hơn nhưng không được hỗ trợ.
// Request access to a bluetooth device whose name starts with "Created by".
// The device named "Created by Francois" has been reported as unsupported.
navigator.bluetooth.requestDevice({
filters: [{
namePrefix: "Created by"
}],
exclusionFilters: [{
name: "Created by Francois"
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Không có bộ lọc nào
Cuối cùng, thay vì filters, bạn có thể dùng phím acceptAllDevices để hiện tất cả các thiết bị Bluetooth ở gần. Bạn cũng cần xác định khoá optionalServices để có thể truy cập vào một số dịch vụ. Nếu không, sau này bạn sẽ gặp lỗi khi tìm cách truy cập vào các tệp đó.
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Kết nối với thiết bị Bluetooth
Vậy bạn sẽ làm gì khi đã có BluetoothDevice? Hãy kết nối với Máy chủ GATT từ xa qua Bluetooth. Máy chủ này lưu giữ các định nghĩa về dịch vụ và đặc điểm.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
// Human-readable name of the device.
console.log(device.name);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });
Đọc một Đặc điểm Bluetooth
Ở đây, chúng ta kết nối với Máy chủ GATT của thiết bị Bluetooth từ xa. Bây giờ, chúng ta muốn nhận một Dịch vụ GATT chính và đọc một đặc điểm thuộc dịch vụ này. Ví dụ: hãy thử đọc mức sạc hiện tại của pin thiết bị.
Trong ví dụ sắp tới, battery_level là Đặc điểm mức pin được chuẩn hoá.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
// Getting Battery Service…
return server.getPrimaryService('battery_service');
})
.then(service => {
// Getting Battery Level Characteristic…
return service.getCharacteristic('battery_level');
})
.then(characteristic => {
// Reading Battery Level…
return characteristic.readValue();
})
.then(value => {
console.log(`Battery percentage is ${value.getUint8(0)}`);
})
.catch(error => { console.error(error); });
Nếu sử dụng một đặc điểm GATT Bluetooth tuỳ chỉnh, bạn có thể cung cấp UUID Bluetooth đầy đủ hoặc một dạng ngắn 16 hoặc 32 bit cho service.getCharacteristic.
Xin lưu ý rằng bạn cũng có thể thêm trình nghe sự kiện characteristicvaluechanged vào một đặc điểm để xử lý việc đọc giá trị của đặc điểm đó. Hãy xem Ví dụ về giá trị đặc điểm đọc đã thay đổi để biết cách xử lý các thông báo GATT sắp tới (không bắt buộc).
…
.then(characteristic => {
// Set up event listener for when characteristic value changes.
characteristic.addEventListener('characteristicvaluechanged',
handleBatteryLevelChanged);
// Reading Battery Level…
return characteristic.readValue();
})
.catch(error => { console.error(error); });
function handleBatteryLevelChanged(event) {
const batteryLevel = event.target.value.getUint8(0);
console.log('Battery percentage is ' + batteryLevel);
}
Ghi vào một Đặc điểm Bluetooth
Việc ghi vào một Đặc điểm GATT của Bluetooth cũng dễ dàng như việc đọc. Lần này, hãy dùng Điểm kiểm soát nhịp tim để đặt lại giá trị của trường Năng lượng tiêu hao thành 0 trên thiết bị đo nhịp tim.
Tôi cam đoan không có phép thuật nào ở đây. Tất cả đều được giải thích trên trang Đặc điểm của điểm kiểm soát nhịp tim.
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
// Writing 1 is the signal to reset energy expended.
const resetEnergyExpended = Uint8Array.of(1);
return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
console.log('Energy expended has been reset.');
})
.catch(error => { console.error(error); });
Nhận thông báo GATT
Bây giờ, hãy xem cách nhận thông báo khi đặc điểm Đo nhịp tim thay đổi trên thiết bị:
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => characteristic.startNotifications())
.then(characteristic => {
characteristic.addEventListener('characteristicvaluechanged',
handleCharacteristicValueChanged);
console.log('Notifications have been started.');
})
.catch(error => { console.error(error); });
function handleCharacteristicValueChanged(event) {
const value = event.target.value;
console.log('Received ' + value);
// TODO: Parse Heart Rate Measurement value.
// See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}
Mẫu Thông báo cho bạn biết cách dừng thông báo bằng stopNotifications() và xoá đúng cách trình nghe sự kiện characteristicvaluechanged đã thêm.
Ngắt kết nối với thiết bị Bluetooth
Để mang lại trải nghiệm tốt hơn cho người dùng, bạn có thể muốn theo dõi các sự kiện ngắt kết nối và mời người dùng kết nối lại:
navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
// Set up event listener for when device gets disconnected.
device.addEventListener('gattserverdisconnected', onDisconnected);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });
function onDisconnected(event) {
const device = event.target;
console.log(`Device ${device.name} is disconnected.`);
}
Bạn cũng có thể gọi device.gatt.disconnect() để ngắt kết nối ứng dụng web khỏi thiết bị Bluetooth. Thao tác này sẽ kích hoạt trình nghe sự kiện gattserverdisconnected hiện có. Xin lưu ý rằng phương thức này sẽ KHÔNG dừng giao tiếp của thiết bị Bluetooth nếu một ứng dụng khác đang giao tiếp với thiết bị Bluetooth. Hãy xem Mẫu ngắt kết nối thiết bị và Mẫu tự động kết nối lại để tìm hiểu sâu hơn.
Đọc và ghi vào các nội dung mô tả Bluetooth
Bộ mô tả GATT Bluetooth là các thuộc tính mô tả một giá trị đặc trưng. Bạn có thể đọc và ghi các giá trị này theo cách tương tự như các đặc điểm GATT của Bluetooth.
Ví dụ: hãy xem cách đọc nội dung mô tả của người dùng về khoảng thời gian đo của nhiệt kế sức khoẻ trên thiết bị.
Trong ví dụ bên dưới, health_thermometer là dịch vụ Nhiệt kế sức khoẻ, measurement_interval là đặc điểm Khoảng đo và gatt.characteristic_user_description là trình mô tả Đặc điểm Mô tả người dùng.
navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => descriptor.readValue())
.then(value => {
const decoder = new TextDecoder('utf-8');
console.log(`User Description: ${decoder.decode(value)}`);
})
.catch(error => { console.error(error); });
Bây giờ, chúng ta đã đọc nội dung mô tả của người dùng về khoảng thời gian đo của nhiệt kế sức khoẻ của thiết bị, hãy xem cách cập nhật nội dung này và ghi một giá trị tuỳ chỉnh.
navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => {
const encoder = new TextEncoder('utf-8');
const userDescription = encoder.encode('Defines the time between measurements.');
return descriptor.writeValue(userDescription);
})
.catch(error => { console.error(error); });
Mẫu, bản minh hoạ và lớp học lập trình
Tất cả mẫu Web Bluetooth dưới đây đều đã được kiểm thử thành công. Để tận hưởng trọn vẹn những mẫu này, bạn nên cài đặt [Ứng dụng Android BLE Peripheral Simulator] mô phỏng một thiết bị ngoại vi BLE có Dịch vụ pin, Dịch vụ đo nhịp tim hoặc Dịch vụ nhiệt kế sức khoẻ.
Cơ bản
- Thông tin thiết bị – truy xuất thông tin cơ bản về thiết bị từ một thiết bị BLE.
- Mức pin – truy xuất thông tin về pin từ một Thiết bị BLE quảng cáo thông tin về Pin.
- Đặt lại năng lượng – đặt lại năng lượng tiêu hao từ Nhịp tim được quảng cáo trên Thiết bị BLE.
- Characteristic Properties (Thuộc tính đặc trưng) – hiển thị tất cả các thuộc tính của một đặc điểm cụ thể trên Thiết bị BLE.
- Thông báo – bắt đầu và dừng thông báo đặc trưng từ một thiết bị BLE.
- Ngắt kết nối thiết bị – ngắt kết nối và nhận thông báo khi một thiết bị BLE bị ngắt kết nối sau khi kết nối với thiết bị đó.
- Get Characteristics (Nhận các đặc điểm) – nhận tất cả các đặc điểm của một dịch vụ được quảng cáo từ Thiết bị BLE.
- Get Descriptors (Nhận nội dung mô tả) – nhận nội dung mô tả của tất cả các đặc điểm của một dịch vụ được quảng cáo từ Thiết bị BLE.
- Bộ lọc dữ liệu của nhà sản xuất – truy xuất thông tin cơ bản về thiết bị từ một Thiết bị BLE khớp với dữ liệu của nhà sản xuất.
- Bộ lọc loại trừ – truy xuất thông tin cơ bản về thiết bị từ một Thiết bị BLE có bộ lọc loại trừ cơ bản.
Kết hợp nhiều thao tác
- Đặc điểm GAP – nhận tất cả đặc điểm GAP của một Thiết bị BLE.
- Đặc điểm thông tin thiết bị – nhận tất cả đặc điểm thông tin thiết bị của một thiết bị BLE.
- Mất kết nối – đặt đặc điểm Cấp độ cảnh báo của Thiết bị BLE (readValue và writeValue).
- Khám phá các dịch vụ và đặc điểm – khám phá tất cả các dịch vụ chính có thể truy cập và đặc điểm của các dịch vụ đó từ một thiết bị BLE.
- Tự động kết nối lại – kết nối lại với một thiết bị BLE đã ngắt kết nối bằng thuật toán thời gian đợi luỹ thừa.
- Đọc giá trị đặc điểm đã thay đổi – đọc mức pin và nhận thông báo về các thay đổi từ Thiết bị BLE.
- Read Descriptors (Đọc nội dung mô tả) – đọc tất cả nội dung mô tả đặc điểm của một dịch vụ từ Thiết bị BLE.
- Write Descriptor (Ghi nội dung mô tả) – ghi vào nội dung mô tả "Characteristic User Description" (Nội dung mô tả đặc điểm người dùng) trên Thiết bị BLE.
Bạn cũng có thể tham khảo các bản minh hoạ Web Bluetooth được tuyển chọn và các lớp học lập trình Web Bluetooth chính thức.
Thư viện
- web-bluetooth-utils là một mô-đun npm bổ sung một số hàm tiện lợi vào API.
- Một shim Web Bluetooth API có trong noble, mô-đun trung tâm BLE Node.js phổ biến nhất. Điều này cho phép bạn webpack/browserify noble mà không cần máy chủ WebSocket hoặc các trình bổ trợ khác.
- angular-web-bluetooth là một mô-đun dành cho Angular, giúp loại bỏ tất cả mã lặp lại cần thiết để định cấu hình Web Bluetooth API.
Công cụ
- Bắt đầu sử dụng Web Bluetooth là một Ứng dụng web đơn giản sẽ tạo tất cả mã chuẩn JavaScript để bắt đầu tương tác với một thiết bị Bluetooth. Nhập tên thiết bị, dịch vụ, đặc điểm, xác định các thuộc tính của thiết bị và bạn có thể bắt đầu.
- Nếu bạn đã là nhà phát triển Bluetooth, thì Trình bổ trợ Web Bluetooth Developer Studio cũng sẽ tạo mã JavaScript Web Bluetooth cho thiết bị Bluetooth của bạn.
Mẹo
Trang Bluetooth Internals (Thông tin nội bộ về Bluetooth) có trong Chrome tại about://bluetooth-internals để bạn có thể kiểm tra mọi thứ về các thiết bị Bluetooth ở gần: trạng thái, dịch vụ, đặc điểm và nội dung mô tả.
Bạn cũng nên xem trang chính thức Cách báo cáo lỗi Web Bluetooth vì đôi khi việc gỡ lỗi Bluetooth có thể gặp khó khăn.
Bước tiếp theo
Trước tiên, hãy kiểm tra trạng thái triển khai trình duyệt và nền tảng để biết những phần nào của Web Bluetooth API hiện đang được triển khai.
Mặc dù vẫn chưa hoàn thiện, nhưng đây là một số điểm chính mà bạn cần lưu ý trong tương lai gần:
- Quá trình quét tìm quảng cáo BLE ở gần sẽ diễn ra với
navigator.bluetooth.requestLEScan(). - Sự kiện
serviceaddedmới sẽ theo dõi các Dịch vụ GATT Bluetooth mới được phát hiện, trong khi sự kiệnserviceremovedsẽ theo dõi các dịch vụ đã bị xoá. Một sự kiệnservicechangedmới sẽ kích hoạt khi có bất kỳ đặc điểm và/hoặc giá trị mô tả nào được thêm hoặc xoá khỏi Dịch vụ GATT Bluetooth.
Thể hiện sự ủng hộ đối với API
Bạn có dự định sử dụng API Web Bluetooth không? Sự ủng hộ công khai của bạn giúp nhóm Chrome ưu tiên các tính năng và cho các nhà cung cấp trình duyệt khác thấy tầm quan trọng của việc hỗ trợ các tính năng đó.
Gửi một tweet đến @ChromiumDev bằng thẻ bắt đầu bằng #WebBluetooth và cho chúng tôi biết bạn đang sử dụng tính năng này ở đâu và như thế nào.
Tài nguyên
- Stack Overflow
- Trạng thái tính năng của Chrome
- Lỗi triển khai Chrome
- Quy cách Web Bluetooth
- Vấn đề về quy cách trên GitHub
- Ứng dụng BLE Peripheral Simulator
Lời cảm ơn
Cảm ơn Kayce Basques đã xem xét.