Web Bluetooth
source link: https://webbluetoothcg.github.io/web-bluetooth/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Abstract
This document describes an API to discover and communicate with devices
over the Bluetooth 4 wireless standard using the Generic Attribute Profile (GATT).
Status of this document
This specification was published by the Web Bluetooth Community Group. It is not a W3C Standard nor is it on the W3C Standards Track.
Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply.
Learn more about W3C Community and Business Groups.
Changes to this document may be tracked at https://github.com/WebBluetoothCG/web-bluetooth/commits/gh-pages.
If you wish to make comments regarding this document, please send them to [email protected] (subscribe, archives).
Table of Contents
1. Introduction
This section is non-normative.
Bluetooth is a standard for short-range wireless communication between devices. Bluetooth "Classic" (BR/EDR) defines a set of binary protocols and supports speeds up to about 24Mbps. Bluetooth 4.0 introduced a new "Low Energy" mode known as "Bluetooth Smart", BLE, or just LE which is limited to about 1Mbps but allows devices to leave their transmitters off most of the time. BLE provides most of its functionality through key/value pairs provided by the Generic Attribute Profile (GATT).
BLE defines multiple roles that devices can play. The Broadcaster and Observer roles are for transmitter- and receiver-only applications, respectively. Devices acting in the Peripheral role can receive connections, and devices acting in the Central role can connect to Peripheral devices.
A device acting in either the Peripheral or Central role can host a GATT Server, which exposes a hierarchy of Services, Characteristics, and Descriptors. See § 5.1 GATT Information Model for more details about this hierarchy. Despite being designed to support BLE transport, the GATT protocol can also run over BR/EDR transport.
The first version of this specification allows web pages, running on a UA in the Central role, to connect to GATT Servers over either a BR/EDR or LE connection. While this specification cites the [BLUETOOTH42] specification, it intends to also support communication among devices that only implement Bluetooth 4.0 or 4.1.
1.1. Examples
let chosenHeartRateService =null; navigator.bluetooth.requestDevice({ filters:[{ services:['heart_rate'],}]}).then(device => device.gatt.connect()).then(server => server.getPrimaryService('heart_rate')).then(service =>{ chosenHeartRateService = service;return Promise.all([ service.getCharacteristic('body_sensor_location').then(handleBodySensorLocationCharacteristic), service.getCharacteristic('heart_rate_measurement').then(handleHeartRateMeasurementCharacteristic),]);});function handleBodySensorLocationCharacteristic(characteristic){if(characteristic ===null){ console.log("Unknown sensor location.");return Promise.resolve();}return characteristic.readValue() .then(sensorLocationData =>{const sensorLocation = sensorLocationData.getUint8(0);switch(sensorLocation){case0:return'Other';case1:return'Chest';case2:return'Wrist';case3:return'Finger';case4:return'Hand';case5:return'Ear Lobe';case6:return'Foot';default:return'Unknown';}}).then(location => console.log(location));}function handleHeartRateMeasurementCharacteristic(characteristic){return characteristic.startNotifications() .then(char=>{ characteristic.addEventListener('characteristicvaluechanged', onHeartRateChanged);});}function onHeartRateChanged(event){const characteristic = event.target; console.log(parseHeartRate(characteristic.value));}
parseHeartRate()
would be defined using the heart_rate_measurement
documentation to read the DataView
stored in a BluetoothRemoteGATTCharacteristic
's value
field.
function parseHeartRate(data){const flags = data.getUint8(0);const rate16Bits = flags &0x1;const result ={};let index =1;if(rate16Bits){ result.heartRate = data.getUint16(index,/*littleEndian=*/true); index +=2;}else{ result.heartRate = data.getUint8(index); index +=1;}const contactDetected = flags &0x2;const contactSensorPresent = flags &0x4;if(contactSensorPresent){ result.contactDetected =!!contactDetected;}const energyPresent = flags &0x8;if(energyPresent){ result.energyExpended = data.getUint16(index,/*littleEndian=*/true); index +=2;}const rrIntervalPresent = flags &0x10;if(rrIntervalPresent){const rrIntervals =[];for(; index +1< data.byteLength; index +=2){ rrIntervals.push(data.getUint16(index,/*littleEndian=*/true));} result.rrIntervals = rrIntervals;}return result;}
onHeartRateChanged()
might log an object like
{ heartRate:70, contactDetected:true, energyExpended:750,// Meaning 750kJ. rrIntervals:[890,870]// Meaning .87s and .85s.}
If the heart rate sensor reports the energyExpended
field, the web
application can reset its value to 0
by writing to the heart_rate_control_point
characteristic:
function resetEnergyExpended(){if(!chosenHeartRateService){return Promise.reject(new Error('No heart rate sensor selected yet.'));}return chosenHeartRateService.getCharacteristic('heart_rate_control_point').then(controlPoint =>{const resetEnergyExpended =new Uint8Array([1]);return controlPoint.writeValue(resetEnergyExpended);});}
2. Security and privacy considerations
2.1. Device access is powerful
When a website requests access to devices using requestDevice()
,
it gets the ability to access all GATT services mentioned in the call. The UA
MUST inform the user what capabilities these services give the website before
asking which devices to entrust to it. If any services in the list aren’t known
to the UA, the UA MUST assume they give the site complete control over the
device and inform the user of this risk. The UA MUST also allow the user to
inspect what sites have access to what devices and revoke these pairings.
The UA MUST NOT allow the user to pair entire classes of devices with a website. It is possible to construct a class of devices for which each individual device sends the same Bluetooth-level identifying information. UAs are not required to attempt to detect this sort of forgery and MAY let a user pair this pseudo-device with a website.
To help ensure that only the entity the user approved for access actually has access, this specification requires that only secure contexts can access Bluetooth devices.
2.2. Trusted servers can serve malicious code
This section is non-normative.
Even if the user trusts an origin, that origin’s servers or developers could be compromised, or the origin’s site could be vulnerable to XSS attacks. Either could lead to users granting malicious code access to valuable devices. Origins should define a Content Security Policy ([CSP3]) to reduce the risk of XSS attacks, but this doesn’t help with compromised servers or developers.
The ability to retrieve granted devices after a page reload, provided by § 3.1 Permission API Integration, makes this risk worse. Instead of having to get the user to grant access while the site is compromised, the attacker can take advantage of previously-granted devices if the user simply visits while the site is compromised. On the other hand, when sites can keep access to devices across page reloads, they don’t have to show as many permission prompts overall, making it more likely that users will pay attention to the prompts they do see.
2.3. Attacks on devices
This section is non-normative.
Communication from websites can break the security model of some devices, which assume they only receive messages from the trusted operating system of a remote device. Human Interface Devices are a prominent example, where allowing a website to communicate would allow that site to log keystrokes. This specification includes a GATT blocklist of such vulnerable services, characteristics, and descriptors to prevent websites from taking advantage of them.
We expect that many devices are vulnerable to unexpected data delivered to their radio. In the past, these devices had to be exploited one-by-one, but this API makes it plausible to conduct large-scale attacks. This specification takes several approaches to make such attacks more difficult:
-
Pairing individual devices instead of device classes requires at least a user action before a device can be exploited.
-
Constraining access to GATT, as opposed to generic byte-stream access, denies malicious websites access to most parsers on the device.
On the other hand, GATT’s Characteristic and Descriptor values are still byte arrays, which may be set to lengths and formats the device doesn’t expect. UAs are encouraged to validate these values when they can.
-
This API never exposes Bluetooth addressing, data signing or encryption keys (Definition of Keys and Values) to websites. This makes it more difficult for a website to predict the bits that will be sent over the radio, which blocks packet-in-packet injection attacks. Unfortunately, this only works over encrypted links, which not all BLE devices are required to support.
UAs can also take further steps to protect their users:
-
A web service may collect lists of malicious websites and vulnerable devices. UAs can deny malicious websites access to any device and any website access to vulnerable devices.
2.4. Bluetooth device identifiers
This section is non-normative.
Each Bluetooth BR/EDR device has a unique 48-bit MAC address known as the BD_ADDR. Each Bluetooth LE device has at least one of a Public Device Address and a Static Device Address. The Public Device Address is a MAC address. The Static Device Address may be regenerated on each restart. A BR/EDR/LE device will use the same value for the BD_ADDR and the Public Device Address (specified in the Read BD_ADDR Command).
An LE device may also have a unique, 128-bit Identity Resolving Key, which is sent to trusted devices during the bonding process. To avoid leaking a persistent identifier, an LE device may scan and advertise using a random Resolvable or Non-Resolvable Private Address instead of its Static or Public Address. These are regenerated periodically (approximately every 15 minutes), but a bonded device can check whether one of its stored IRKs matches any given Resolvable Private Address using the Resolvable Private Address Resolution Procedure.
Each Bluetooth device also has a human-readable Bluetooth Device Name. These aren’t guaranteed to be unique, but may well be, depending on the device type.
2.4.1. Identifiers for remote Bluetooth devices
This section is non-normative.
If a website can retrieve any of the persistent device IDs, these can be used, in combination with a large effort to catalog ambient devices, to discover a user’s location. A device ID can also be used to identify that a user who pairs two different websites with the same Bluetooth device is a single user. On the other hand, many GATT services are available that could be used to fingerprint a device, and a device can easily expose a custom GATT service to make this easier.
This specification suggests that the UA use different device IDs for a single device when its user doesn’t intend scripts to learn that it’s a single device, which makes it difficult for websites to abuse the device address like this. Device makers can still design their devices to help track users, but it takes work.
2.4.2. The UA’s Bluetooth address
This section is non-normative.
In BR/EDR mode, or in LE mode during active scanning without the Privacy Feature, the UA broadcasts its persistent ID to any nearby Bluetooth radio. This makes it easy to scatter hostile devices in an area and track the UA. As of 2014-08, few or no platforms document that they implement the Privacy Feature, so despite this spec recommending it, few UAs are likely to use it. This spec does require a user gesture for a website to trigger a scan, which reduces the frequency of scans some, but it would still be better for more platforms to expose the Privacy Feature.
2.5. Exposing Bluetooth availability
This section is non-normative.
navigator.bluetooth.
exposes whether a
Bluetooth radio is available on the user’s system, regardless of whether it is
powered on or not. The availability is also affected if the user has configured
the UA to block Web Bluetooth. Some users might consider this private, although
it’s hard to imagine the damage that would result from revealing it. This
information also increases the UA’s fingerprinting surface by a bit. This
function returns a getAvailability()
Promise
, so UAs have the option of asking the user what
value they want to return, but we expect the increased risk to be small enough
that UAs will choose not to prompt.
3. Device Discovery
dictionaryBluetoothDataFilterInit
{ BufferSourcedataPrefix
; BufferSourcemask
; }; dictionaryBluetoothLEScanFilterInit
{ sequence<BluetoothServiceUUID> services; DOMString name; DOMString namePrefix; // Maps unsigned shorts to BluetoothDataFilters. object manufacturerData; // Maps BluetoothServiceUUIDs to BluetoothDataFilters. object serviceData; }; dictionaryRequestDeviceOptions
{ sequence<BluetoothLEScanFilterInit> filters; sequence<BluetoothServiceUUID> optionalServices = []; boolean acceptAllDevices = false; }; [Exposed=Window, SecureContext] interfaceBluetooth
: EventTarget { Promise<boolean> getAvailability(); attributeEventHandleronavailabilitychanged
; [SameObject] readonlyattributeBluetoothDevice? referringDevice; Promise<sequence<BluetoothDevice>> getDevices(); Promise<BluetoothDevice> requestDevice(optionalRequestDeviceOptionsoptions
= {}); }; Bluetooth includesBluetoothDeviceEventHandlers; Bluetooth includesCharacteristicEventHandlers; Bluetooth includesServiceEventHandlers;
Bluetooth
membersgetAvailability()
informs the page whether Bluetooth is
available at all. An adapter that’s disabled through software should count as
available. Changes in availability, for example when the user physically
attaches or detaches an adapter, are reported through the availabilitychanged
event.
referringDevice
gives access to the device from which the user
opened this page, if any. For example, an Eddystone beacon
might advertise a URL, which the UA allows the user to open. A BluetoothDevice
representing the beacon would be available through navigator.bluetooth.
. referringDevice
getDevices()
enables the page to retrieve Bluetooth devices that
the user has granted access to.
requestDevice(options)
asks the user to grant this origin access
to a device that matches any filter in options.
. To match a filter, the
device has to:filters
-
support all the GATT service UUIDs in the
services
list if that member is present, -
have a name equal to
name
if that member is present, -
have a name starting with
namePrefix
if that member is present, -
advertise manufacturer specific data matching all of the key/value pairs in
manufacturerData
if that member is present, and -
advertise service data matching all of the key/value pairs in
serviceData
if that member is present.
Both Manufacturer Specific Data and Service Data map a key to an
array of bytes. BluetoothDataFilterInit
filters these arrays. An array
matches if it has a prefix such that prefix &
is
equal to mask
. dataPrefix
& mask
Note that if a device changes its behavior significantly when it connects, for example by not advertising its identifying manufacturer data anymore and instead having the client discover some identifying GATT services, the website may need to include filters for both behaviors.
In rare cases, a device may not advertise enough distinguishing information to
let a site filter out uninteresting devices. In those cases, a site can set acceptAllDevices
to true
and omit
all filters
. This puts the burden of selecting the
right device entirely on the site’s users. If a site uses acceptAllDevices
, it will only be able to use services
listed in optionalServices
.
After the user selects a device to pair with this origin, the origin is allowed
to access any service whose UUID was listed in the services
list in any element of options.filters
or in options.
.optionalServices
This implies that if developers filter just by name, they must use optionalServices
to get access to any services.
If the website calls
navigator.bluetooth.requestDevice({ filters:[{services:[A, B]}]});
the user will be shown a dialog containing devices D1 and D2. If the user selects D1, the website will not be able to access services C or D. If the user selects D2, the website will not be able to access service E.
On the other hand, if the website calls
navigator.bluetooth.requestDevice({ filters:[{services:[A, B]},{services:[C, D]}]});
the dialog will contain devices D1, D2, and D3, and if the user selects D1, the website will be able to access services A, B, C, and D.
If the website then calls
navigator.bluetooth.getDevices();
the resulting Promise
will resolve into an array containing device D1, and
the website will be able to access services A, B, C, and D.
The optionalServices
list doesn’t add any devices to the dialog the
user sees, but it does affect which services the website can use from the device
the user picks.
navigator.bluetooth.requestDevice({ filters:[{services:[A, B]}], optionalServices:[E]});
Shows a dialog containing D1 and D2, but not D4, since D4 doesn’t contain the required services. If the user selects D2, unlike in the first example, the website will be able to access services A, B, and E.
If the website calls
navigator.bluetooth.getDevices();
again, then the resulting Promise
will resolve into an array containing the
devices D1 and D2. The A, B, C, and D services will be accessible on device D1,
while A, B, and E services will be accessible on device D2.
The allowed services also apply if the device changes after the user grants
access. For example, if the user selects D1 in the previous requestDevice()
call, and D1 later adds a new E service, that will
fire the serviceadded
event, and the web page will be able to access service
E.
The following table shows which devices the user can select between
for several values of filters passed to navigator.bluetooth.requestDevice({filters: filters})
.
[{name:"Unique Name"}]D5
[{namePrefix:"Device"}]D3, D4
[{name:"First De"},{name:"First Device"}]<none> D1 only advertises a prefix of its name, so trying to match its whole name fails.
[{namePrefix:"First"},{name:"Unique Name"}]D1, D5
[{services:[C], namePrefix:"Device"},{name:"Unique Name"}]D3, D5
The following table shows which devices the user can select between for several
values of filters passed to navigator.bluetooth.requestDevice({filters: filters})
.
[{manufacturerData:{17:{}}}]D1
[{serviceData:{"A":{}}}]D2
[{manufacturerData:{17:{}}},{serviceData:{"A":{}}}]D1, D2
[{manufacturerData:{17:{}}, serviceData:{"A":{}}}]<none>
[{manufacturerData:{17:{dataPrefix:new Uint8Array([1,2,3])},}}]D1
[{manufacturerData:{17:{dataPrefix:new Uint8Array([1,2,3,4])},}}]<none>
[{manufacturerData:{17:{dataPrefix:new Uint8Array([1])},}}]D1
[{manufacturerData:{17:{dataPrefix:new Uint8Array([0x91,0xAA]), mask:new Uint8Array([0x0F,0x57])},}}]D1
[{manufacturerData:{17:{},18:{},}}]<none>
TypeError
s.
To accept all devices, use acceptAllDevices
instead.
Call
Notes
requestDevice({})Invalid: An absent list of filters doesn’t accept any devices.
requestDevice({filters:[]})Invalid: An empty list of filters doesn’t accept any devices.
requestDevice({filters:[{}]})Invalid: An empty filter accepts all devices, and so isn’t allowed either.
requestDevice({ acceptAllDevices:true})Valid: Explicitly accept all devices with
acceptAllDevices
.
requestDevice({ filters:[...], acceptAllDevices:true})Invalid:
acceptAllDevices
would override any filters
.
requestDevice({ filters:[{namePrefix:""}]})Invalid:
namePrefix
, if present, must be non-empty to filter devices.
requestDevice({ filters:[{manufacturerData:{}}]})Invalid:
manufacturerData
, if present,
must be non-empty to filter devices.
requestDevice({ filters:[{serviceData:{}}]})Invalid:
serviceData
, if present,
must be non-empty to filter devices.
Instances of Bluetooth
are created with the internal slots described in the following table:
[[deviceInstanceMap]]
An empty map from Bluetooth devices
to BluetoothDevice
instances.
Ensures only one BluetoothDevice
instance represents each Bluetooth
device inside a single global object.
[[attributeInstanceMap]]
An empty map from Bluetooth cache entries to Promise
s.
The Promise
s resolve to either BluetoothRemoteGATTService
, BluetoothRemoteGATTCharacteristic
, or BluetoothRemoteGATTDescriptor
instances.
[[referringDevice]]
null
Set to a BluetoothDevice
while initializing the Document
object if the Document
was opened from the device.
navigator.bluetooth.referringDevice
must return [[referringDevice]]
.
If this happens, then as part of initializing the Document
object,
the UA MUST run the following steps:
-
Let referringDevice be the device that caused the navigation.
-
Get the
BluetoothDevice
representing referringDevice insidenavigator.bluetooth
, and let referringDeviceObj be the result. -
If the previous step threw an exception, abort these steps.
Note: This means the UA didn’t infer that the user intended to grant the current realm access to referringDevice. For example, the user might have denied GATT access globally. -
Set
navigator.bluetooth.
to referringDeviceObj.[[referringDevice]]
match
:
-
If
filter.
is present then, if device’s Bluetooth Device Name isn’t complete and equal toname
filter.name
, returnmismatch
. -
If
filter.
is present then if device’s Bluetooth Device Name isn’t present or doesn’t start withnamePrefix
filter.namePrefix
, returnmismatch
. -
For each uuid in
filter.
, if the UA has not received advertising data, an extended inquiry response, or a service discovery response indicating that the device supports a primary (vs included) service with UUID uuid, returnservices
mismatch
. -
If
filter.
is present then for each manufacturerId inmanufacturerData
filter.manufacturerData.
, if device hasn’t advertised manufacturer specific data with a company identifier code that stringifies in base 10 to manufacturerId and with data that matches[[OwnPropertyKeys]]
()filter.
returnmanufacturerData
[manufacturerId]mismatch
. -
If
filter.
is present then for each uuid inserviceData
filter.
, if device hasn’t advertised service data with a UUID whose 128-bit form is uuid and with data that matchesserviceData
.[[OwnPropertyKeys]]
()filter.
, returnserviceData
[uuid]mismatch
. -
Return
match
.
BluetoothDataFilterInit
filter if the following steps return match
.
-
Let expectedPrefix be a copy of the bytes held by
filter.
.dataPrefix
-
Let mask be a copy of the bytes held by
filter.
.mask
-
If data has fewer bytes than expectedPrefix, return
mismatch
. -
For each
1
bit in mask, if the corresponding bit in data is not equal to the corresponding bit in expectedPrefix, returnmismatch
. -
Return
match
.
getDevices()
method, when
invoked and given a BluetoothPermissionStorage
storage, MUST return a new promise promise and run the following steps in parallel:
-
Let devices be a new empty
Array
. -
For each allowedDevice in
storage.
, add theallowedDevices
BluetoothDevice
object representing allowedDevice@[[device]]
to devices. -
Resolve promise with devices.
Note: TheBluetoothDevice
s in devices may not be in range of the Bluetooth radio. For a given device in devices, thewatchAdvertisements()
method can be used to observe when device is in range and broadcasting advertisement packets. When anadvertisementreceived
event event is fired on a device, it may indicate that it is close enough for a connection to be established by callingevent.device.gatt.
.connect()
requestDevice(options)
method, when invoked, MUST return a new promise promise and run the following steps in parallel:
-
If
options.
is present andfilters
options.
isacceptAllDevices
true
, or ifoptions.
is not present andfilters
options.
isacceptAllDevices
false
, reject promise with aTypeError
and abort these steps.Note: This enforces that exactly one offilters
or
is present.acceptAllDevices
:true -
Request Bluetooth devices, passing
options.
iffilters
options.
isacceptAllDevices
false
ornull
otherwise, and passingoptions.
, and let devices be the result.optionalServices
-
If the previous step threw an exception, reject promise with that exception and abort these steps.
-
If devices is an empty sequence, reject promise with a
NotFoundError
and abort these steps. -
Resolve promise with
devices[0]
.
BluetoothPermissionStorage
storage and a sequence of BluetoothLEScanFilterInit
s, filters, which can be null
to represent that
all devices can match, and a sequence of BluetoothServiceUUID
s, optionalServices, the UA MUST run the following steps:
-
Check that the algorithm is triggered while its relevant global object has a transient activation, otherwise throw a
SecurityError
and abort these steps. -
In order to convert the arguments from service names and aliases to just UUIDs, do the following sub-steps:
-
If
filters !== null && filters.length === 0
, throw aTypeError
and abort these steps. -
Let uuidFilters be a new
Array
and requiredServiceUUIDs be a newSet
. -
If filters is
null
, then set requiredServiceUUIDs to the set of all UUIDs. -
If filters isn’t
null
, then for each filter in filters, do the following steps:-
Let canonicalFilter be the result of canonicalizing filter.
-
Append canonicalFilter to uuidFilters.
-
Add the contents of
canonicalFilter.services
to requiredServiceUUIDs.
-
-
Let optionalServiceUUIDs be
.Array.prototype.map
.call(optionalServices,BluetoothUUID.getService
) -
If any of the
BluetoothUUID.getService()
calls threw an exception, throw that exception and abort these steps. -
Remove from optionalServiceUUIDs any UUIDs that are blocklisted.
-
-
Let descriptor be
{ name:"bluetooth", filters:uuidFilters optionalServices:optionalServiceUUIDs, acceptAllDevices:filters !==null,}
-
Let state be descriptor’s permission state.
-
If state is
"denied"
, return[]
and abort these steps. -
If the UA can prove that no devices could possibly be found in the next step, for example because there is no Bluetooth adapter with which to scan, or because the filters can’t be matched by any possible advertising packet, the UA MAY return
[]
and abort these steps. -
Scan for devices with requiredServiceUUIDs as the set of Service UUIDs, and let scanResult be the result.
-
If filters isn’t null, remove devices from scanResult if they do not match a filter in uuidFilters.
-
Even if scanResult is empty, prompt the user to choose one of the devices in scanResult, associated with descriptor, and let device be the result.
The UA MAY allow the user to select a nearby device that does not match uuidFilters.
Note: The UA should show the user the human-readable name of each device. If this name is not available because, for example, the UA’s Bluetooth system doesn’t support privacy-enabled scans, the UA should allow the user to indicate interest and then perform a privacy-disabled scan to retrieve the name. -
The UA MAY add device to storage.
Note: Choosing a device probably indicates that the user intends that device to appear in theallowedDevices
list of"bluetooth"
's extra permission data for at least the current settings object, for itsmayUseGATT
field to betrue
, and for all the services in the union of requiredServiceUUIDs and optionalServiceUUIDs to appear in itsallowedServices
list, in addition to any services that were already there. -
If device is
"denied"
, return[]
and abort these steps. -
The UA MAY populate the Bluetooth cache with all Services inside device. Ignore any errors from this step.
-
Get the
BluetoothDevice
representing device inside the context object, propagating any exception, and let deviceObj be the result. -
Return
[deviceObj]
.
BluetoothLEScanFilterInit
filter, is the BluetoothLEScanFilterInit
returned from the following steps:
-
If none of filter’s members is present, throw a
TypeError
and abort these steps. -
Let canonicalizedFilter be
{}
. -
If
filter.
is present, do the following sub-steps:services
-
If
filter.services.length === 0
, throw aTypeError
and abort these steps. -
Let services be
.Array.prototype.map
.call(filter.services,BluetoothUUID.getService
) -
If any of the
BluetoothUUID.getService()
calls threw an exception, throw that exception and abort these steps. -
If any service in services is blocklisted, throw a
SecurityError
and abort these steps. -
Set
canonicalizedFilter.services
to services.
-
-
If
filter.
is present, do the following sub-steps.name
-
If the UTF-8 encoding of
filter.name
is more than 248 bytes long, throw aTypeError
and abort these steps.Note: 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name. -
Set
canonicalizedFilter.name
tofilter.name
.
-
-
If
filter.
is present, do the following sub-steps.namePrefix
-
If
filter.namePrefix.length === 0
or if the UTF-8 encoding offilter.namePrefix
is more than 248 bytes long, throw aTypeError
and abort these steps.Note: 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name. -
Set
canonicalizedFilter.namePrefix
tofilter.namePrefix
.
-
-
Set
canonicalizedFilter.manufacturerData
to{}
. -
If
filter.
is present, do the following sub-steps for each key inmanufacturerData
filter.manufacturerData.
. If there are no such keys, throw a[[OwnPropertyKeys]]
()TypeError
and abort these steps.-
Let manufacturerId be CanonicalNumericIndexString(key).
-
If manufacturerId is
undefined
or-0
, or IsInteger(manufacturerId) isfalse
, or manufacturerId is outside the range from 0–65535 inclusive, throw aTypeError
and abort these steps. -
Let dataFilter be
filter.manufacturerData[manufacturerId]
, converted to an IDL value of typeBluetoothDataFilterInit
. If this conversion throws an exception, propagate it and abort these steps. -
Let canonicalizedDataFilter be the result of canonicalizing dataFilter, converted to an ECMAScript value. If this throws an exception, propagate that exception and abort these steps.
-
Call CreateDataProperty (canonicalizedFilter.manufacturerData, key, canonicalizedDataFilter).
-
-
Set
canonicalizedFilter.serviceData
to{}
. -
If
filter.
is present, do the following sub-steps for each key inserviceData
filter.serviceData.
. If there are no such keys, throw a[[OwnPropertyKeys]]
()TypeError
and abort these steps.-
Let serviceName be CanonicalNumericIndexString(key).
-
If serviceName is
undefined
, set serviceName to key. -
Let service be
.BluetoothUUID.getService
(serviceName) -
If the previous step threw an exception, throw that exception and abort these steps.
-
If service is blocklisted, throw a
SecurityError
and abort these steps. -
Let dataFilter be
filter.serviceData[service]
, converted to an IDL value of typeBluetoothDataFilterInit
. If this conversion throws an exception, propagate it and abort these steps. -
Let canonicalizedDataFilter be the result of canonicalizing dataFilter, converted to an ECMAScript value. If this throws an exception, propagate that exception and abort these steps.
-
Call CreateDataProperty(canonicalizedFilter.serviceData, service, canonicalizedDataFilter).
-
-
Return canonicalizedFilter.
BluetoothDataFilterInit
filter, is the BluetoothDataFilterInit
returned from the following steps:
-
If
filter.
is present, let dataPrefix be a copy of the bytes held bydataPrefix
filter.dataPrefix
. Otherwise, let dataPrefix be an empty sequence of bytes. -
If
filter.
is present, let mask be a copy of the bytes held bymask
filter.mask
. Otherwise, let mask be a sequence of0xFF
bytes the same length as dataPrefix. -
If mask is not the same length as dataPrefix, throw a
TypeError
and abort these steps. -
Return
{dataPrefix: new Uint8Array(|dataPrefix|), mask: new Uint8Array(|mask|)}
.
-
If the UA has scanned for devices recently with a set of UUIDs that was a superset of the UUIDs for the current scan, then the UA MAY return the result of that scan and abort these steps.
TODO: Nail down the amount of time.
-
Let nearbyDevices be a set of Bluetooth devices, initially equal to the set of devices that are connected (have an ATT Bearer) to the UA.
-
If the UA supports the LE transport, perform the General Discovery Procedure, except that the UA may include devices that have no Discoverable Mode flag set, and add the discovered Bluetooth devices to nearbyDevices. The UA SHOULD enable the Privacy Feature.
Both passive scanning and the Privacy Feature avoid leaking the unique, immutable device ID. We ought to require UAs to use either one, but none of the OS APIs appear to expose either. Bluetooth also makes it hard to use passive scanning since it doesn’t require Central devices to support the Observation Procedure.
-
If the UA supports the BR/EDR transport, perform the Device Discovery Procedure and add the discovered Bluetooth devices to nearbyDevices.
All forms of BR/EDR inquiry/discovery appear to leak the unique, immutable device address.
-
Let result be a set of Bluetooth devices, initially empty.
-
For each Bluetooth device device in nearbyDevices, do the following sub-steps:
-
If device’s supported physical transports include LE and its Bluetooth Device Name is partial or absent, the UA SHOULD perform the Name Discovery Procedure to acquire a complete name.
-
If device’s advertised Service UUIDs have a non-empty intersection with the set of Service UUIDs, add device to result and abort these sub-steps.
Note: For BR/EDR devices, there is no way to distinguish GATT from non-GATT services in the Extended Inquiry Response. If a site filters to the UUID of a non-GATT service, the user may be able to select a device for the result ofrequestDevice
that this API provides no way to interact with. -
The UA MAY connect to device and populate the Bluetooth cache with all Services whose UUIDs are in the set of Service UUIDs. If device’s supported physical transports include BR/EDR, then in addition to the standard GATT procedures, the UA MAY use the Service Discovery Protocol (Searching for Services) when populating the cache.
Note: Connecting to every nearby device to discover services costs power and can slow down other use of the Bluetooth radio. UAs should only discover extra services on a device if they have some reason to expect that device to be interesting.UAs should also help developers avoid relying on this extra discovery behavior. For example, say a developer has previously connected to a device, so the UA knows the device’s full set of supported services. If this developer then filters using a non-advertised UUID, the dialog they see may include this device, even if the filter would likely exclude the device on users' machines. The UA could provide a developer option to warn when this happens or to include only advertised services in matching filters.
-
If the Bluetooth cache contains known-present Services inside device with UUIDs in the set of Service UUIDs, the UA MAY add device to result.
-
-
Return result from the scan.
We need a way for a site to register to receive an event when an interesting device comes within range.
BluetoothPermissionStorage
storage given a set of requiredServiceUUIDs and a set of optionalServiceUUIDs, the
UA MUST run the following steps:
-
Let grantedServiceUUIDs be a new
Set
. -
Add the contents of requiredServiceUUIDs to grantedServiceUUIDs.
-
Add the contents of optionalServiceUUIDs to grantedServiceUUIDs.
-
Search for an element allowedDevice in
storage.
where device is equal toallowedDevices
allowedDevice@
. If one is found, perform the following sub-steps:[[device]]
-
Add the contents of
allowedDevice.
to grantedServiceUUIDs.allowedServices
If one is not found, perform the following sub-steps:
-
Let allowedDevice.
deviceId
be a unique ID to the extent that the UA can determine that two Bluetooth connections are the same device and to the extent that the user wants to expose that fact to script.
-
-
Set allowedDevice.
allowedServices
to grantedServiceUUIDs. -
Set allowedDevice.
mayUseGATT
totrue
.
3.1. Permission API Integration
The [permissions] API provides a uniform way for websites to request permissions from users and query which permissions they have.
navigator.permissions.request
({name:"bluetooth",...})
as an alternate
spelling of navigator.bluetooth.requestDevice()
.
navigator.permissions.request({ name:"bluetooth", filters:[{ services:['heart_rate'],}]}).then(result =>{if(result.devices.length >=1){return result.devices[0];}else{thrownewDOMException("Chooser cancelled","NotFoundError");}}).then(device =>{ sessionStorage.lastDevice = device.id;});
navigator.permissions.query
({name:"bluetooth",...})
to retrieve those
devices after a reload.
navigator.permissions.query({ name:"bluetooth", deviceId: sessionStorage.lastDevice,}).then(result =>{if(result.devices.length ==1){return result.devices[0];}else{thrownewDOMException("Lost permission","NotFoundError");}}).then(...);
The "bluetooth"
powerful
feature’s permission-related algorithms and types are defined as follows:
dictionaryextra permission data typeBluetoothPermissionDescriptor
: PermissionDescriptor { DOMStringdeviceId
; // These match RequestDeviceOptions. sequence<BluetoothLEScanFilterInit>filters
; sequence<BluetoothServiceUUID>optionalServices
= []; booleanacceptAllDevices
= false; };
BluetoothPermissionStorage
, defined as:
dictionaryAllowedBluetoothDevice
{ requiredDOMStringdeviceId
; requiredbooleanmayUseGATT
; // An allowedServices of "all" means all services are allowed. required (DOMString orsequence<UUID>)allowedServices
; }; dictionaryBluetoothPermissionStorage
{ requiredsequence<AllowedBluetoothDevice>allowedDevices
; };
AllowedBluetoothDevice
instances have an internal slot [[device]]
that holds a Bluetooth device.
allowedDevices
must have
different [[device]]
s and different deviceId
s.
If mayUseGATT
is false
, allowedServices
must be []
.
deviceId
allows a site to track that a BluetoothDevice
instance seen at one time represents the same device
as another BluetoothDevice
instance seen at another time, possibly in
a different realm. UAs should consider whether their user intends
that tracking to happen or not-happen when returning "bluetooth"
's extra permission data.
For example, users generally don’t intend two different origins to know that they’re interacting with the same device, and they generally don’t intend unique identifiers to persist after they’ve cleared an origin’s cookies.
[Exposed=Window] interfacepermission request algorithm To request the "bluetooth" permission with aBluetoothPermissionResult
: PermissionStatus { attributeFrozenArray<BluetoothDevice>devices
; };
BluetoothPermissionDescriptor
options and a BluetoothPermissionResult
status,
the UA MUST run the following steps:
-
If
options.
is present andfilters
options.
isacceptAllDevices
true
, or ifoptions.
is not present andfilters
options.
isacceptAllDevices
false
, throw aTypeError
.Note: This enforces that exactly one offilters
or
is present.acceptAllDevices
:true -
Request Bluetooth devices, passing
options.
iffilters
options.
isacceptAllDevices
false
ornull
otherwise, and passingoptions.
, propagating any exception, and let devices be the result.optionalServices
-
Set
status.devices
to a newFrozenArray
whose contents are the elements of devices.
BluetoothPermissionDescriptor
desc and a BluetoothPermissionResult
status, the UA must:
-
Let global be the relevant global object for status.
-
Set
status.
to desc’s permission state.state
-
If
status.
isstate
"denied"
, setstatus.devices
to an emptyFrozenArray
and abort these steps. -
Let matchingDevices be a new
Array
. -
Let storage, a
BluetoothPermissionStorage
, be"bluetooth"
's extra permission data for the current settings object. -
For each allowedDevice in
storage.allowedDevices
, run the following sub-steps:-
If
desc.deviceId
is set andallowedDevice.deviceId != desc.deviceId
, continue to the next allowedDevice. -
If
desc.filters
is set, do the following sub-steps:-
Replace each filter in
desc.filters
with the result of canonicalizing it. If any of these canonicalizations throws an error, return that error and abort these steps. -
If
allowedDevice.
does not match a filter in[[device]]
desc.filters
, continue to the next allowedDevice.
-
-
Get the
BluetoothDevice
representingallowedDevice.
within[[device]]
global.navigator.bluetooth
, and add the result to matchingDevices.
Note: Thedesc.optionalServices
field does not affect the result. -
-
Set
status.devices
to a newFrozenArray
whose contents are matchingDevices.
-
Let storage, a
BluetoothPermissionStorage
, be"bluetooth"
's extra permission data for the current settings object. -
For each
BluetoothDevice
instance deviceObj in the current realm, run the following sub-steps:-
If there is an
AllowedBluetoothDevice
allowedDevice instorage.
such that:allowedDevices
-
allowedDevice.
is the same device as[[device]]
deviceObj.
, and[[representedDevice]]
then update
deviceObj.
to be[[allowedServices]]
allowedDevice.
, and continue to the next deviceObj.allowedServices
-
-
Otherwise, detach deviceObj from its device by running the remaining steps.
-
Call
deviceObj.gatt.
.disconnect()
Note: This fires agattserverdisconnected
event at deviceObj. -
Set
deviceObj.
to[[representedDevice]]
null
.
-
3.2. Overall Bluetooth availability
The UA may be running on a computer that has no Bluetooth radio. requestDevice()
handles this by failing to discover any devices, which
results in a NotFoundError
, but websites may be able to handle it more
gracefully.
const bluetoothUI = document.querySelector('#bluetoothUI'); navigator.bluetooth.getAvailability().then(isAvailable =>{ bluetoothUI.hidden =!isAvailable;}); navigator.bluetooth.addEventListener('availabilitychanged', e =>{ bluetoothUI.hidden =!e.value;});
getAvailability()
method,
when invoked, MUST return a new promise promise and run the following
steps in parallel:
-
If the user has configured the UA to return a particular answer from this function for the current origin, queue a task to resolve promise with the configured answer, and abort these steps.
Note: If the Web Bluetooth permission has been blocked by the user, the UA may resolve promise withfalse
. -
If the UA is running on a system that has a Bluetooth radio queue a task to resolve promise with
true
regardless of the powered state of the Bluetooth radio. -
Otherwise, queue a task to resolve promise with
false
.Note: The promise is resolved in parallel to let the UA call out to other systems to determine whether Bluetooth is available.
getAvailability
promise with false, the following can be used to
detect when Bluetooth is available again to show Bluetooth UI:
function checkAvailability(){const bluetoothUI = document.querySelector('#bluetoothUI'); navigator.bluetooth.getAvailability().then(isAvailable =>{ bluetoothUI.hidden =!isAvailable;});} navigator.permissions.query({name:"bluetooth"}).then(status =>{if(status.state !=='denied') checkAvailability();// Bluetooth is blocked, listen for change in PermissionStatus. status.onchange =()=>{if(this.state !=='denied') checkAvailability();};});
getAvailability()
, the UA must queue a task on each global
object global’s responsible event loop to run the following steps:
-
Let oldAvailability be the value
getAvailability()
would have returned before the change. -
Let newAvailability be the value
getAvailability()
would return after the change. -
If oldAvailability is not the same as newAvailability, fire an event named
availabilitychanged
using theValueEvent
interface atglobal.navigator.bluetooth
with itsvalue
attribute initialized to newAvailability.
[ Exposed=Window, SecureContext ] interfaceValueEvent
: Event {constructor
(DOMStringtype
, optionalValueEventInitinitDict
= {}); readonlyattributeanyvalue; }; dictionaryValueEventInit
: EventInit { anyvalue
= null; };
ValueEvent
instances are constructed as specified in DOM §2.5 Constructing events.
The value
attribute must return the value
it was initialized to.
Such a generic event type belongs in [HTML] or [DOM], not here.
4. Device Representation
The UA needs to track Bluetooth device properties at several levels: globally, per origin, and per global object.
4.1. Global Bluetooth device properties
The physical Bluetooth device may be guaranteed to have some properties that the UA may not have received. Those properties are described as optional here.
A Bluetooth device has the following properties. Optional properties are not present, and sequence and map properties are empty, unless/until described otherwise. Other properties have a default specified or are specified when a device is introduced.
-
A set of supported physical transports, including one or both of BR/EDR and LE. This set will generally be filled based on the transports over which the device was discovered and the Flags Data Type in the Advertising Data or Extended Inquiry Response.
-
One or more of several kinds of 48-bit address: a Public Bluetooth Address, a (random) Static Address, and a resolvable or non-resolvable Private Address.
-
An optional 128-bit Identity Resolving Key.
-
An optional partial or complete Bluetooth Device Name. A device has a partial name when the Shortened Local Name AD data was received, but the full name hasn’t been read yet. The Bluetooth Device Name is encoded as UTF-8 and converted to a DOMString using the utf-8 decode without BOM algorithm.
-
An optional ATT Bearer, over which all GATT communication happens. The ATT Bearer is created by procedures described in "Connection Establishment" under GAP Interoperability Requirements. It is disconnected in ways [BLUETOOTH42] isn’t entirely clear about.
-
A list of advertised Service UUIDs from the Advertising Data or Extended Inquiry Response.
-
A hierarchy of GATT Attributes.
The UA SHOULD determine that two Bluetooth devices are the same Bluetooth device if and only if they have the same Public Bluetooth Address, Static Address, Private Address, or Identity Resolving Key, or if the Resolvable Private Address Resolution Procedure succeeds using one device’s IRK and the other’s Resolvable Private Address. However, because platform APIs don’t document how they determine device identity, the UA MAY use another procedure.
4.2. BluetoothDevice
A BluetoothDevice
instance represents a Bluetooth device for a
particular global object (or, equivalently, for a particular Realm or Bluetooth
instance).
[Exposed=Window, SecureContext] interfaceBluetoothDevice
: EventTarget { readonlyattributeDOMString id; readonlyattributeDOMString? name; readonlyattributeBluetoothRemoteGATTServer? gatt; Promise<void> watchAdvertisements( optionalWatchAdvertisementsOptionsoptions
= {}); readonlyattributeboolean watchingAdvertisements; }; BluetoothDevice includesBluetoothDeviceEventHandlers; BluetoothDevice includesCharacteristicEventHandlers; BluetoothDevice includesServiceEventHandlers; dictionaryWatchAdvertisementsOptions
{ AbortSignalsignal
; };
BluetoothDevice
attributesid
uniquely identifies a device to the extent that the UA can
determine that two Bluetooth connections are to the same device and to the
extent that the user wants to expose that
fact to script.
name
is the human-readable name of the device.
gatt
provides a way to interact with this device’s GATT
server if the site has permission to do so.
watchingAdvertisements
is true if the UA is currently scanning for
advertisements from this device and firing events for them.
Instances of BluetoothDevice
are created with the internal slots described in the following table:
[[context]]
<always set in prose>
The Bluetooth
object that returned this BluetoothDevice
.
[[representedDevice]]
<always set in prose>
The Bluetooth device this object represents,
or null
if access has been revoked.
[[gatt]]
a new BluetoothRemoteGATTServer
instance with its device
attribute initialized to this
and
its connected
attribute initialized to false
.
Does not change.
[[allowedServices]]
<always set in prose>
This device’s allowedServices
list for this
origin or "all"
if all services are allowed. For example, a UA may grant
an origin access to all services on a referringDevice
that advertised
a URL on that origin.
[[watchAdvertisementsState]]
'not-watching'
An string enumeration describing the current state of a watchAdvertisements()
operation. The possible
enumeration values are:
-
'not-watching'
-
'pending-watch'
-
'watching'
BluetoothDevice
representing a Bluetooth device device inside a Bluetooth
instance context, the UA MUST run the following steps:
-
Let storage, a
BluetoothPermissionStorage
, be"bluetooth"
's extra permission data for the current settings object. -
Find the allowedDevice in
storage.
withallowedDevices
allowedDevice.
the same device as device. If there is no such object, throw a[[device]]
SecurityError
and abort these steps. -
If there is no key in context.
[[deviceInstanceMap]]
that is the same device as device, run the following sub-steps:-
Let result be a new instance of
BluetoothDevice
. -
Initialize all of result’s optional fields to
null
. -
Initialize
result.
to context.[[context]]
-
Initialize
result.
to device.[[representedDevice]]
-
Initialize
result.id
toallowedDevice.
, and initializedeviceId
result.
to[[allowedServices]]
allowedDevice.
.allowedServices
-
If device has a partial or complete Bluetooth Device Name, set
result.name
to that string. -
Initialize
result.watchingAdvertisements
tofalse
. -
Add a mapping from device to result in context.
[[deviceInstanceMap]]
.
-
-
Return the value in context.
[[deviceInstanceMap]]
whose key is the same device as device.
gatt
attribute MUST perform the following steps:
A user agent has an associated watch advertisements manager which is the result of starting a new parallel queue.
watchAdvertisements(options)
method, when invoked, MUST return a new promise promise and
run the following steps:
-
If
options.
is present, then perform the following sub-steps:signal
-
If
this.
is:[[watchAdvertisementsState]]
'not-watching'
-
Set
this.
to[[watchAdvertisementsState]]
'pending-watch'
. -
Enqueue the following steps to the watch advertisements manager, but abort when
this.
becomes[[watchAdvertisementsState]]
not-watching
:-
Ensure that the UA is scanning for this device’s advertisements. The UA SHOULD NOT filter out "duplicate" advertisements for the same device.
-
If the UA fails to enable scanning, queue a task to perform the following steps, and abort these steps:
-
Set
this.
to[[watchAdvertisementsState]]
'not-watching'
. -
Reject promise with one of the following errors:
The UA doesn’t support scanning for advertisements Bluetooth is turned off Other reasons
-
-
Queue a task to perform the following steps, but abort when
this.
becomes[[watchAdvertisementsState]]
not-watching
:
-
'pending-watch'
'watching'
-
Resolve promise with
undefined
.
-
-
If aborted, reject promise with
AbortError
.
Note: Scanning costs power, so websites should avoid watching for advertisements
unnecessarily, and should use their AbortController
to stop using power
as soon as possible.
watchAdvertisements
for a BluetoothDevice
device, run these steps:
-
Set
this.
to[[watchAdvertisementsState]]
'not-watching'
. -
Set
device.
towatchingAdvertisements
false
. -
Enqueue the following steps to watch advertisements manager:
-
If no more
BluetoothDevice
s in the whole UA havewatchingAdvertisements
set totrue
, the UA SHOULD stop scanning for advertisements. Otherwise, if no moreBluetoothDevice
s representing the same device asthis
havewatchingAdvertisements
set totrue
, the UA SHOULD reconfigure the scan to avoid receiving reports for this device.
-
watchAdvertisements
operations, run these steps:
4.2.1. Handling Visibility Change
Operations that initiate a scan for Bluetooth devices may only run in a visible document. When visibility state is no longer "visible"
, scanning operations for that document need to be
aborted.
4.2.2. Handling Document Loss of Full Activity
Operations that initiate a scan for Bluetooth devices may only run in a fully active document. When full activity is lost, scanning operations for that document need to be aborted.
4.2.3. Responding to Advertising Events
When an advertising event arrives for a BluetoothDevice
with watchingAdvertisements
set,
the UA delivers an "advertisementreceived
" event.
[Exposed=Window, SecureContext] interfaceBluetoothManufacturerDataMap { readonlymaplike<unsignedshort, DataView>; }; [Exposed=Window, SecureContext] interfaceBluetoothServiceDataMap { readonlymaplike<UUID, DataView>; }; [ Exposed=Window, SecureContext ] interfaceBluetoothAdvertisingEvent
: Event { constructor(DOMStringtype
, BluetoothAdvertisingEventInitinit
); [SameObject] readonlyattributeBluetoothDevice device; readonlyattributeFrozenArray<UUID> uuids; readonlyattributeDOMString? name; readonlyattributeunsignedshort? appearance; readonlyattributebyte? txPower; readonlyattributebyte? rssi; [SameObject] readonlyattributeBluetoothManufacturerDataMap manufacturerData; [SameObject] readonlyattributeBluetoothServiceDataMap serviceData; }; dictionaryBluetoothAdvertisingEventInit
: EventInit { requiredBluetoothDevicedevice
; sequence<(DOMString orunsignedlong)>uuids
; DOMStringname
; unsignedshortappearance
; bytetxPower
; byterssi
; BluetoothManufacturerDataMapmanufacturerData
; BluetoothServiceDataMapserviceData
; };
BluetoothAdvertisingEvent
attributesdevice
is the BluetoothDevice
that sent this advertisement.
uuids
lists the Service UUIDs that this advertisement says device
's GATT server supports.
name
is device
's local name, or a prefix of it.
appearance
is an Appearance, one of the values defined by the org.bluetooth.characteristic.gap.appearance
characteristic.
txPower
is the transmission power at which the device is
broadcasting, measured in dBm. This is used to compute the path loss as this.txPower - this.rssi
.
rssi
is the power at which the advertisement was received, measured
in dBm. This is used to compute the path loss as this.txPower -
this.rssi
.
manufacturerData
maps unsigned short
Company Identifier
Codes to DataView
s.
requestDevice
dialog.
var known_service ="A service in the iBeacon’s GATT server";return navigator.bluetooth.requestDevice({ filters:[{services:[known_service]}]}).then(device =>{ device.watchAdvertisements(); device.addEventListener('advertisementreceived', interpretIBeacon);});function interpretIBeacon(event){var rssi = event.rssi;var appleData = event.manufacturerData.get(0x004C);if(appleData.byteLength !=23|| appleData.getUint16(0,false)!==0x0215){ console.log({isBeacon:false});}var uuidArray =new Uint8Array(appleData.buffer,2,16);var major = appleData.getUint16(18,false);var minor = appleData.getUint16(20,false);var txPowerAt1m =-appleData.getInt8(22); console.log({ isBeacon:true, uuidArray, major, minor, pathLossVs1m: txPowerAt1m - rssi});});
The format of iBeacon advertisements was derived from How do iBeacons work? by Adam Warski.
-
Let device be the Bluetooth device that sent the advertising event.
-
For each
BluetoothDevice
deviceObj in the UA such that device is the same device asdeviceObj.
, queue a task on deviceObj’s relevant settings object’s responsible event loop to do the following sub-steps:[[representedDevice]]
-
If
deviceObj.
iswatchingAdvertisements
false
, abort these sub-steps. -
Fire an
advertisementreceived
event for the advertising event at deviceObj.
-
advertisementreceived
event for an advertising event adv at a BluetoothDevice
deviceObj,
the UA MUST perform the following steps:
-
Let event be
{ bubbles:true, device:deviceObj, uuids:[], manufacturerData:new Map(), serviceData:new Map()}
-
If the received signal strength is available for any packet in adv, set
event.rssi
to this signal strength in dBm. -
For each AD structure in adv’s advertising packet and scan response, select from the following steps depending on the AD type:
Incomplete List of 16-bit Service UUIDs Complete List of 16-bit Service UUIDs Incomplete List of 32-bit Service UUIDs Complete List of 32-bit Service UUIDs Incomplete List of 128-bit Service UUIDs Complete List of 128-bit Service UUIDs Append the listed UUIDs toevent.uuids
. Shortened Local Name Complete Local Name UTF-8 decode without BOM the AD data and setevent.name
to the result.Note: We don’t expose whether the name is complete because existing APIs require reading the raw advertisement to get this information, and we want more evidence that it’s useful before adding a field to the API.Manufacturer Specific Data Add toevent.manufacturerData
a mapping from the 16-bit Company Identifier Code to anArrayBuffer
containing the manufacturer-specific data. TX Power Level Setevent.txPower
to the AD data. Service Data - 16 bit UUID Service Data - 32 bit UUID Service Data - 128 bit UUID Add toevent.serviceData
a mapping from the UUID to anArrayBuffer
containing the service data. Appearance Setevent.appearance
to the AD data. Otherwise Skip to the next AD structure. -
Fire an event initialized as
new
, with itsBluetoothAdvertisingEvent
("advertisementreceived
", event)isTrusted
attribute initialized totrue
, at deviceObj.
All fields in BluetoothAdvertisingEvent
return the last value they were
initialized or set to.
BluetoothAdvertisingEvent(type, init)
constructor MUST perform the following steps:
-
Let event be the result of running the steps from DOM §2.5 Constructing events except for the
uuids
,manufacturerData
, andserviceData
members. -
If
init.uuids
is set, initializeevent.uuids
to a newFrozenArray
containing the elements ofinit.uuids.map(
. Otherwise initializeBluetoothUUID.getService
)event.uuids
to an emptyFrozenArray
. -
For each mapping in
init.manufacturerData
:-
Let code be the key converted to an
unsigned short
. -
Let value be the value.
-
If value is not a
BufferSource
, throw aTypeError
. -
Let bytes be a new read only ArrayBuffer containing a copy of the bytes held by value.
-
Add a mapping from code to
new DataView(bytes)
inevent.manufacturerData.
.[[BackingMap]]
-
-
For each mapping in
init.serviceData
:-
Let key be the key.
-
Let service be the result of calling
BluetoothUUID.
getService
(key). -
Let value be the value.
-
If value is not a
BufferSource
, throw aTypeError
. -
Let bytes be a new read only ArrayBuffer containing a copy of the bytes held by value.
-
Add a mapping from service to
new DataView(bytes)
inevent.serviceData.
.[[BackingMap]]
-
-
Return event.
4.2.3.1. BluetoothManufacturerDataMap
Instances of BluetoothManufacturerDataMap
have a [[BackingMap]]
slot because they are maplike, which maps manufacturer codes to
the manufacturer’s data, converted to DataView
s.
4.2.3.2. BluetoothServiceDataMap
Instances of BluetoothServiceDataMap
have a [[BackingMap]]
slot because they are maplike, which maps service UUIDs to the
service’s data, converted to DataView
s.
5. GATT Interaction
5.1. GATT Information Model
Profiles are purely logical: the specification of a Profile describes the expected interactions between the other GATT entities the Profile contains, but it’s impossible to query which Profiles a device supports.
GATT Clients can discover and interact with the Services, Characteristics, and Descriptors on a device using a set of GATT procedures. This spec refers to Services, Characteristics, and Descriptors collectively as Attributes. All Attributes have a type that’s identified by a UUID. Each Attribute also has a 16-bit Attribute Handle that distinguishes it from other Attributes of the same type on the same GATT Server. Attributes are notionally ordered within their GATT Server by their Attribute Handle, but while platform interfaces provide attributes in some order, they do not guarantee that it’s consistent with the Attribute Handle order.
A Service contains a collection of Included Services and Characteristics. The Included Services are references to other Services, and a single Service can be included by more than one other Service. Services are known as Primary Services if they appear directly under the GATT Server, and Secondary Services if they’re only included by other Services, but Primary Services can also be included.
A Characteristic contains a value, which is an array of bytes, and a collection of Descriptors. Depending on the properties of the Characteristic, a GATT Client can read or write its value, or register to be notified when the value changes.
Finally, a Descriptor contains a value (again an array of bytes) that describes or configures its Characteristic.
5.1.1. Persistence across connections
The Bluetooth Attribute Caching system allows bonded clients to
save references to attributes from one connection to the next. Web Bluetooth
treats websites as not bonded to devices they have permission to
access: BluetoothRemoteGATTService
, BluetoothRemoteGATTCharacteristic
,
and BluetoothRemoteGATTDescriptor
objects become invalid on disconnection, and the site must retrieved
them again when it re-connects.
5.1.2. The Bluetooth cache
The UA MUST maintain a Bluetooth cache of the
hierarchy of Services, Characteristics, and Descriptors it has discovered on a
device. The UA MAY share this cache between multiple origins accessing the same
device. Each potential entry in the cache is either known-present, known-absent,
or unknown. The cache MUST NOT contain two entries that are for the same
attribute. Each known-present entry in the cache is associated with an
optional Promise<
, BluetoothRemoteGATTService
>Promise<
, or BluetoothRemoteGATTCharacteristic
>Promise<
instance for each BluetoothRemoteGATTDescriptor
>Bluetooth
instance.
serviceA.getCharacteristic(uuid1)
function with an initially empty Bluetooth cache, the UA uses the Discover Characteristics by UUID procedure to fill the needed cache entries, and the UA ends the procedure early
because it only needs one Characteristic to fulfil the returned Promise
,
then the first Characteristic with UUID uuid1
inside serviceA
is known-present, and any subsequent Characteristics with
that UUID remain unknown. If the user later calls serviceA.getCharacteristics(uuid1)
, the UA needs to resume or
restart the Discover Characteristics by UUID procedure. If it turns out
that serviceA
only has one Characteristic with UUID uuid1
, then the subsequent Characteristics become known-absent. The known-present entries in the Bluetooth cache are ordered: Primary Services appear in a particular order within a device, Included Services and Characteristics appear in a particular order within Services, and Descriptors appear in a particular order within Characteristics. The order SHOULD match the order of Attribute Handles on the device, but UAs MAY use another order if the device’s order isn’t available.
-
Attempt to make all matching entries in the cache either known-present or known-absent, using any sequence of GATT procedures that [BLUETOOTH42] specifies will return enough information. Handle errors as described in § 5.7 Error handling.
-
If the previous step returns an error, return that error from this algorithm.
BluetoothDevice
instance deviceObj for entries matching some description, the UA MUST return a deviceObj.gatt
-connection-checking wrapper around a new promise promise and run the following steps in
parallel:
-
Populate the Bluetooth cache with entries matching the description.
-
If the previous step returns an error, reject promise with that error and abort these steps.
-
Let entries be the sequence of known-present cache entries matching the description.
-
Let context be
deviceObj.
.[[context]]
-
Let result be a new sequence.
-
For each entry in entries:
-
If entry has no associated
Promise<BluetoothGATT*>
instance in context.[[attributeInstanceMap]]
, create aBluetoothRemoteGATTService
representing entry, create aBluetoothRemoteGATTCharacteristic
representing entry, or create aBluetoothRemoteGATTDescriptor
representing entry, depending on whether entry is a Service, Characteristic, or Descriptor, and add a mapping from entry to the resultingPromise
in context.[[attributeInstanceMap]]
. -
Append to result the
Promise<BluetoothGATT*>
instance associated with entry in context.[[attributeInstanceMap]]
.
-
-
Resolve promise with the result of waiting for all elements of result.
5.1.3. Navigating the Bluetooth Hierarchy
single: boolean,
uuidCanonicalizer: function,
uuid: optional
(DOMString or unsigned int)
,allowedUuids: optional
("all" or Array<DOMString>)
,child type: GATT declaration type),
the UA MUST perform the following steps:
-
If uuid is present, set it to uuidCanonicalizer(uuid). If uuidCanonicalizer threw an exception, return a promise rejected with that exception and abort these steps.
-
If uuid is present and is blocklisted, return a promise rejected with a
SecurityError
and abort these steps. -
Let deviceObj be, depending on the type of attribute:
BluetoothDevice
attribute
BluetoothRemoteGATTService
attribute.
device
BluetoothRemoteGATTCharacteristic
attribute.
service
.device
-
If
deviceObj.gatt.
isconnected
false
, return a promise rejected with with aNetworkError
and abort these steps. -
If Represented(attribute) is
null
, return a promise rejected with anInvalidStateError
and abort these steps.Note: This happens when a Service or Characteristic is removed from the device or invalidated by a disconnection, and then its object is used again.
-
Query the Bluetooth cache in
deviceObj
for entries that:-
are within Represented(attribute),
-
have a type described by child type,
-
have a UUID that is not blocklisted,
-
if uuid is present, have a UUID of uuid,
-
if allowedUuids is present and not
"all"
, have a UUID in allowedUuids, and -
if the single flag is set, are the first of these.
Let promise be the result.
-
-
Upon fulfillment of promise with result, run the following steps:
-
If result is empty, throw a
NotFoundError
, -
Otherwise, if the single flag is set, returns the first (only) element of result.
-
Otherwise, return result.
-
5.1.4. Identifying Services, Characteristics, and Descriptors
When checking whether two Services, Characteristics, or Descriptors a and b are the same attribute, the UA SHOULD determine that they are the same if a and b are inside the same device and have the same Attribute Handle, but MAY use any algorithm it wants with the constraint that a and b MUST NOT be considered the same attribute if they fit any of the following conditions:
-
They are not both Services, both Characteristics, or both Descriptors.
-
They are both Services, but are not both primary or both secondary services.
-
They have different UUIDs.
-
Their parent Devices aren’t the same device or their parent Services or Characteristics aren’t the same attribute.
x === y
returns whether the objects represent the same
attribute, because of how the query the Bluetooth cache algorithm
creates and caches new objects. 5.2. BluetoothRemoteGATTServer
BluetoothRemoteGATTServer
represents a GATT Server on a remote device.
[Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTServer
{ [SameObject] readonlyattributeBluetoothDevice device; readonlyattributeboolean connected; Promise<BluetoothRemoteGATTServer> connect(); voiddisconnect(); Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUIDservice
); Promise<sequence<BluetoothRemoteGATTService>> getPrimaryServices(optionalBluetoothServiceUUIDservice
); };
BluetoothRemoteGATTServer
attributesdevice
is the device running this server.
connected
is true while this instance is connected to this.device
. It can be false while the UA is physically connected,
for example when there are other connected BluetoothRemoteGATTServer
instances for other global objects.
When no ECMAScript code can
observe an instance of BluetoothRemoteGATTServer
server anymore,
the UA SHOULD run server.
.disconnect()
BluetoothDevice
instances are stored in navigator.bluetooth.[[deviceInstanceMap]]
, this can’t
happen at least until navigation releases the global object or closing the tab
or window destroys the browsing context. Instances of BluetoothRemoteGATTServer
are created with the internal
slots described in the following table:
[[activeAlgorithms]]
new Set
()
Contains a Promise
corresponding to each algorithm using this server’s
connection. disconnect()
empties this set so that the algorithm can
tell whether its realm was ever disconnected while it was running.
connect()
method, when invoked, MUST perform the following steps:
-
Let promise be a new promise.
-
If
this.device.
is[[representedDevice]]
null
, queue a task to reject promise with aNetworkError
, return promise, and abort these steps. -
If the UA is currently using the Bluetooth system, it MAY queue a task to reject promise with a
NetworkError
, return promise, and abort these steps.Implementations may be able to avoid this
NetworkError
, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> -
Add promise to
this.
.[[activeAlgorithms]]
-
Return promise and run the following steps in parallel:
-
If
this.device.
has no ATT Bearer, do the following sub-steps:[[representedDevice]]
-
Attempt to create an ATT Bearer using the procedures described in "Connection Establishment" under GAP Interoperability Requirements. Abort this attempt if promise is removed from
this.
.[[activeAlgorithms]]
Note: These procedures can wait forever if a connectable advertisement isn’t received. The website should calldisconnect()
if it no longer wants to connect. -
If this attempt was aborted because promise was removed from
this.
, reject promise with an[[activeAlgorithms]]
AbortError
and abort these steps. -
If this attempt failed for another reason, reject promise with a
NetworkError
and abort these steps. -
Use the Exchange MTU procedure to negotiate the largest supported MTU. Ignore any errors from this step.
-
The UA MAY attempt to bond with the remote device using the BR/EDR Bonding Procedure or the LE Bonding Procedure.
Note: We would normally prefer to give the website control over whether and when bonding happens, but the Core Bluetooth platform API doesn’t provide a way for UAs to implement such a knob. Having a bond is more secure than not having one, so this specification allows the UA to opportunistically create one on platforms where that’s possible. This may cause a user-visible pairing dialog to appear when a connection is created, instead of when a restricted characteristic is accessed.
-
-
Queue a task to perform the following sub-steps:
-
disconnect()
method, when invoked, MUST perform the following steps:
-
If systems that aren’t using this API, either inside or outside of the UA, are using the device’s ATT Bearer, abort this algorithm.
-
For all
BluetoothDevice
sdeviceObj
in the whole UA:-
If
deviceObj.
is not the same device as device, continue to the next deviceObj.[[representedDevice]]
-
If
deviceObj.gatt.
isconnected
true
, abort this algorithm. -
If
deviceObj.gatt.
contains the[[activeAlgorithms]]
Promise
of a call toconnect()
, abort this algorithm.
-
-
Destroy device’s ATT Bearer.
BluetoothRemoteGATTServer
was
disconnected while they were running, even if the UA stays connected the whole
time and the BluetoothRemoteGATTServer
is subsequently re-connected before
they finish. We wrap the returned Promise
to accomplish this. To create a gattServer-connection-checking wrapper around a Promise
promise, the UA MUST:
-
If
gattServer.connected
istrue
, add promise togattServer.
.[[activeAlgorithms]]
-
React to promise:
-
If promise was fulfilled with value result, then:
-
If promise is in
gattServer.
, remove it and return result.[[activeAlgorithms]]
-
Otherwise, throw a
NetworkError
.Note: This error is thrown because gattServer was disconnected during the execution of the main algorithm.
-
-
If promise was rejected with reason error, then:
-
If promise is in
gattServer.
, remove it and throw error.[[activeAlgorithms]]
-
Otherwise, throw a
NetworkError
.Note: This error is thrown because gattServer was disconnected during the execution of the main algorithm.
-
-
getPrimaryService(service)
method, when invoked, MUST perform the following steps:
-
If
this.device.
is not[[allowedServices]]
"all"
and service is not inthis.device.
, return a promise rejected with a[[allowedServices]]
SecurityError
and abort these steps. -
Return GetGATTChildren(attribute=
this.device
,
single=true,
uuidCanonicalizer=BluetoothUUID.getService
,
uuid=service
,
allowedUuids=this.device.
,[[allowedServices]]
child type="GATT Primary Service")
getPrimaryServices(service)
method, when invoked, MUST perform the following steps:
-
If
this.device.
is not[[allowedServices]]
"all"
, and service is present and not inthis.device.
, return a promise rejected with a[[allowedServices]]
SecurityError
and abort these steps. -
Return GetGATTChildren(attribute=
this.device
,
single=false,
uuidCanonicalizer=BluetoothUUID.getService
,
uuid=service
,
allowedUuids=this.device.
,[[allowedServices]]
child type="GATT Primary Service")
5.3. BluetoothRemoteGATTService
BluetoothRemoteGATTService
represents a GATT Service, a collection of
characteristics and relationships to other services that encapsulate the
behavior of part of a device.
[Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTService
: EventTarget { [SameObject] readonlyattributeBluetoothDevice device; readonlyattributeUUID uuid; readonlyattributeboolean isPrimary; Promise<BluetoothRemoteGATTCharacteristic> getCharacteristic(BluetoothCharacteristicUUIDcharacteristic
); Promise<sequence<BluetoothRemoteGATTCharacteristic>> getCharacteristics(optionalBluetoothCharacteristicUUIDcharacteristic
); Promise<BluetoothRemoteGATTService> getIncludedService(BluetoothServiceUUIDservice
); Promise<sequence<BluetoothRemoteGATTService>> getIncludedServices(optionalBluetoothServiceUUIDservice
); }; BluetoothRemoteGATTService includesCharacteristicEventHandlers; BluetoothRemoteGATTService includesServiceEventHandlers;
BluetoothRemoteGATTService
attributesdevice
is the BluetoothDevice
representing the remote peripheral
that the GATT service belongs to.
uuid
is the UUID of the service, e.g. '0000180d-0000-1000-8000-00805f9b34fb'
for the Heart Rate service.
isPrimary
indicates whether the type of this service is primary or
secondary.
Instances of BluetoothRemoteGATTService
are created with the internal
slots described in the following table:
[[representedService]]
<always set in prose>
The Service this object represents,
or null
if the Service has been removed or otherwise invalidated.
BluetoothRemoteGATTService
representing a
Service service, the UA must return a new promise promise and run the following steps in parallel.
-
Let result be a new instance of
BluetoothRemoteGATTService
with its[[representedService]]
slot initialized to service. -
Get the
BluetoothDevice
representing the device in which service appears, and let device be the result. -
If the previous step threw an error, reject promise with that error and abort these steps.
-
Initialize
result.device
from device. -
Initialize
result.uuid
from the UUID of service. -
If service is a Primary Service, initialize
result.isPrimary
to true. Otherwise initializeresult.isPrimary
to false. -
Resolve promise with result.
getCharacteristic(characteristic)
method retrieves a Characteristic inside this Service. When invoked, it MUST return
GetGATTChildren(attribute=
this
,
single=true,
uuidCanonicalizer=BluetoothUUID.getCharacteristic
,
uuid=characteristic
,
allowedUuids=undefined
,
child type="GATT Characteristic")
getCharacteristics(characteristic)
method retrieves a
list of Characteristics inside this Service. When invoked, it MUST return
GetGATTChildren(attribute=
this
,
single=false,
uuidCanonicalizer=BluetoothUUID.getCharacteristic
,
uuid=characteristic
,
allowedUuids=undefined
,
child type="GATT Characteristic")
getIncludedService(service)
method retrieves an Included Service inside this Service. When invoked, it MUST return
GetGATTChildren(attribute=
this
,
single=true,
uuidCanonicalizer=BluetoothUUID.getService
,
uuid=service
,
allowedUuids=undefined
,
child type="GATT Included Service")
getIncludedServices(service)
method retrieves a list of Included Services inside this Service. When invoked, it MUST return
GetGATTChildren(attribute=
this
,
single=false,
uuidCanonicalizer=BluetoothUUID.getService
,
uuid=service
,
allowedUuids=undefined
,
child type="GATT Included Service")
5.4. BluetoothRemoteGATTCharacteristic
BluetoothRemoteGATTCharacteristic
represents a GATT Characteristic,
which is a basic data element that provides further information about a
peripheral’s service.
[Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTCharacteristic
: EventTarget { [SameObject] readonlyattributeBluetoothRemoteGATTService service; readonlyattributeUUID uuid; readonlyattributeBluetoothCharacteristicProperties properties; readonlyattributeDataView? value; Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUIDdescriptor
); Promise<sequence<BluetoothRemoteGATTDescriptor>> getDescriptors(optionalBluetoothDescriptorUUIDdescriptor
); Promise<DataView> readValue(); Promise<void> writeValue(BufferSourcevalue
); Promise<void> writeValueWithResponse(BufferSourcevalue
); Promise<void> writeValueWithoutResponse(BufferSourcevalue
); Promise<BluetoothRemoteGATTCharacteristic> startNotifications(); Promise<BluetoothRemoteGATTCharacteristic> stopNotifications(); }; BluetoothRemoteGATTCharacteristic includesCharacteristicEventHandlers;
BluetoothRemoteGATTCharacteristic
attributesservice
is the GATT service this characteristic belongs to.
uuid
is the UUID of the characteristic, e.g. '00002a37-0000-1000-8000-00805f9b34fb'
for the Heart Rate Measurement characteristic.
properties
holds the properties of this characteristic.
value
is the currently cached characteristic value. This value gets
updated when the value of the characteristic is read or updated via a
notification or indication.
Instances of BluetoothRemoteGATTCharacteristic
are created with the internal slots described in the following table:
[[representedCharacteristic]]
<always set in prose>
The Characteristic this object represents, or null
if the
Characteristic has been removed or otherwise invalidated.
BluetoothRemoteGATTCharacteristic
representing a Characteristic characteristic, the UA must
return a new promise promise and run the following steps in
parallel.
-
Let result be a new instance of
BluetoothRemoteGATTCharacteristic
with its[[representedCharacteristic]]
slot initialized to characteristic. -
Initialize
result.service
from theBluetoothRemoteGATTService
instance representing the Service in which characteristic appears. -
Initialize
result.uuid
from the UUID of characteristic. -
Create a
BluetoothCharacteristicProperties
instance from the Characteristic characteristic, and let propertiesPromise be the result. -
Wait for propertiesPromise to settle.
-
If propertiesPromise was rejected, resolve promise with propertiesPromise and abort these steps.
-
Initialize
result.properties
from the value propertiesPromise was fulfilled with. -
Initialize
result.value
tonull
. The UA MAY initializeresult.value
to a newDataView
wrapping a newArrayBuffer
containing the most recently read value from characteristic if this value is available. -
Resolve promise with result.
getDescriptor(descriptor)
method retrieves a Descriptor inside this Characteristic. When invoked, it MUST return
GetGATTChildren(attribute=
this
,
single=true,
uuidCanonicalizer=BluetoothUUID.getDescriptor
,
uuid=descriptor
,
allowedUuids=undefined
,
child type="GATT Descriptor")
getDescriptors(descriptor)
method retrieves a list of Descriptors inside this Characteristic. When invoked, it MUST return
GetGATTChildren(attribute=
this
,
single=false,
uuidCanonicalizer=BluetoothUUID.getDescriptor
,
uuid=descriptor
,
allowedUuids=undefined
,
child type="GATT Descriptor")
readValue()
method, when invoked, MUST run the following steps:
-
If
this.uuid
is blocklisted for reads, return a promise rejected with aSecurityError
and abort these steps. -
If
this.service.device.gatt.
isconnected
false
, return a promise rejected with aNetworkError
and abort these steps. -
Let characteristic be
this.
.[[representedCharacteristic]]
-
If characteristic is
null
, return a promise rejected with anInvalidStateError
and abort these steps. -
Return a
this.service.device.gatt
-connection-checking wrapper around a new promise promise and run the following steps in parallel:-
If the
Read
bit is not set in characteristic’s properties, reject promise with aNotSupportedError
and abort these steps. -
If the UA is currently using the Bluetooth system, it MAY reject promise with a
NetworkError
and abort these steps.Implementations may be able to avoid this
NetworkError
, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> -
Use any combination of the sub-procedures in the Characteristic Value Read procedure to retrieve the value of characteristic. Handle errors as described in § 5.7 Error handling.
-
If the previous step returned an error, reject promise with that error and abort these steps.
-
Queue a task to perform the following steps:
-
If promise is not in
this.service.device.gatt.
, reject promise with a[[activeAlgorithms]]
NetworkError
and abort these steps. -
Let buffer be an
ArrayBuffer
holding the retrieved value, and assignnew DataView(buffer)
tothis.value
. -
Fire an event named
characteristicvaluechanged
with itsbubbles
attribute initialized totrue
atthis
. -
Resolve promise with
this.value
.
-
-
value: BufferSource,
response: string),
the UA MUST perform the following steps:
-
If
this.uuid
is blocklisted for writes, return a promise rejected with aSecurityError
and abort these steps. -
Let bytes be a copy of the bytes held by
value
. -
If bytes is more than 512 bytes long (the maximum length of an attribute value, per Long Attribute Values) return a promise rejected with an
InvalidModificationError
and abort these steps. -
If
this.service.device.gatt.
isconnected
false
, return a promise rejected with aNetworkError
and abort these steps. -
Let characteristic be
this.
.[[representedCharacteristic]]
-
If characteristic is
null
, return a promise rejected with anInvalidStateError
and abort these steps. -
Return a
this.service.device.gatt
- connection-checking wrapper around a new promise promise and run the following steps in parallel.-
Assert: response is one of "required", "never", or "optional".
-
If the UA is currently using the Bluetooth system, it MAY reject promise with a
NetworkError
and abort these steps.Implementations may be able to avoid this
NetworkError
, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> -
Write bytes to characteristic by performing the following steps:
If response is "required" Use the Write Characteristic Value procedure. If response is "never" Use the Write Without Response procedure. Otherwise Use any combination of the sub-procedures in the Characteristic Value Write procedure. Handle errors as described in § 5.7 Error handling. -
If the previous step returned an error, reject promise with that error and abort these steps.
-
Queue a task to perform the following steps:
-
If promise is not in
this.service.device.gatt.
, reject promise with a[[activeAlgorithms]]
NetworkError
and abort these steps. -
Set
this.value
to a newDataView
wrapping a newArrayBuffer
containing bytes. -
Resolve promise with
undefined
.
-
-
writeValueWithResponse()
and writeValueWithoutResponse()
instead.
The
method, when invoked, MUST return writeValue(value)
WriteCharacteristicValue( this=
this
,
value=value
,
response="optional")
This method is for backwards compatibility only. New implementations should not implement this method. <https://github.com/WebBluetoothCG/web-bluetooth/issues/238>
writeValueWithResponse(value)
method, when invoked, MUST
return
WriteCharacteristicValue( this=
this
,
value=value
,
response="required")
writeValueWithoutResponse(value)
method, when invoked,
MUST return
WriteCharacteristicValue( this=
this
,
value=value
,
response="never")
The UA MUST maintain a map from each known GATT Characteristic to a set
of Bluetooth
objects known as the characteristic’s active notification
context set.
navigator.bluetooth
objects for each Realm that
has registered for notifications. All notifications become inactive when a
device is disconnected. A site that wants to keep getting notifications after
reconnecting needs to call startNotifications()
again, and there is an
unavoidable risk that some notifications will be missed in the gap before startNotifications()
takes effect. startNotifications()
method, when invoked, MUST return a new
promise promise and run the following steps in parallel.
See § 5.6.4 Responding to Notifications and Indications for details of receiving notifications.
-
If
this.uuid
is blocklisted for reads, reject promise with aSecurityError
and abort these steps. -
If
this.service.device.gatt.
isconnected
false
, reject promise with aNetworkError
and abort these steps. -
Let characteristic be
this.
.[[representedCharacteristic]]
-
If characteristic is
null
, return a promise rejected with anInvalidStateError
and abort these steps. -
If neither of the
Notify
orIndicate
bits are set in characteristic’s properties, reject promise with aNotSupportedError
and abort these steps. -
If characteristic’s active notification context set contains
navigator.bluetooth
, resolve promise withthis
and abort these steps. -
If the UA is currently using the Bluetooth system, it MAY reject promise with a
NetworkError
and abort these steps.Implementations may be able to avoid this
NetworkError
, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> -
If the characteristic has a Client Characteristic Configuration descriptor, use any of the Characteristic Descriptors procedures to ensure that one of the
Notification
orIndication
bits in characteristic’s Client Characteristic Configuration descriptor is set, matching the constraints in characteristic’s properties. The UA SHOULD avoid setting both bits, and MUST deduplicate value-change events if both bits are set. Handle errors as described in § 5.7 Error handling.Note: Some devices have characteristics whose properties include the Notify or Indicate bit but that don’t have a Client Characteristic Configuration descriptor. These non-standard-compliant characteristics tend to send notifications or indications unconditionally, so this specification allows applications to simply subscribe to their messages. -
If the previous step returned an error, reject promise with that error and abort these steps.
-
Add
navigator.bluetooth
to characteristic’s active notification context set. -
Resolve promise with
this
.
.then
handler of the result promise. stopNotifications()
method, when invoked, MUST return a new
promise promise and run the following steps in parallel:
-
Let characteristic be
this.
.[[representedCharacteristic]]
-
If characteristic is
null
, return a promise rejected with anInvalidStateError
and abort these steps. -
If characteristic’s active notification context set contains
navigator.bluetooth
, remove it. -
If characteristic’s active notification context set became empty and the characteristic has a Client Characteristic Configuration descriptor, the UA SHOULD use any of the Characteristic Descriptors procedures to clear the
Notification
andIndication
bits in characteristic’s Client Characteristic Configuration descriptor. -
Queue a task to resolve promise with
this
.
5.4.1. BluetoothCharacteristicProperties
Each BluetoothRemoteGATTCharacteristic
exposes its characteristic
properties through a BluetoothCharacteristicProperties
object. These
properties express what operations are valid on the characteristic.
[Exposed=Window, SecureContext] interfaceBluetoothCharacteristicProperties
{ readonlyattributebooleanbroadcast
; readonlyattributebooleanread
; readonlyattributebooleanwriteWithoutResponse
; readonlyattributebooleanwrite
; readonlyattributebooleannotify
; readonlyattributebooleanindicate
; readonlyattributebooleanauthenticatedSignedWrites
; readonlyattributebooleanreliableWrite
; readonlyattributebooleanwritableAuxiliaries
; };
BluetoothCharacteristicProperties
instance from
the Characteristic characteristic, the UA MUST return a new
promise promise and run the following steps in parallel:
-
Let propertiesObj be a new instance of
BluetoothCharacteristicProperties
. -
Let properties be the characteristic properties of characteristic.
-
Initialize the attributes of propertiesObj from the corresponding bits in properties:
Attribute Bitbroadcast
Broadcastread
ReadwriteWithoutResponse
Write Without Responsewrite
Writenotify
Notifyindicate
IndicateauthenticatedSignedWrites
Authenticated Signed Writes -
If the Extended Properties bit of the characteristic properties is not set, initialize
propertiesObj.reliableWrite
andpropertiesObj.writableAuxiliaries
tofalse
. Otherwise, run the following steps:-
Discover the Characteristic Extended Properties descriptor for characteristic and read its value into extendedProperties. Handle errors as described in § 5.7 Error handling.
Characteristic Extended Properties isn’t clear whether the extended properties are immutable for a given Characteristic. If they are, the UA should be allowed to cache them.
-
If the previous step returned an error, reject promise with that error and abort these steps.
-
Initialize
propertiesObj.reliableWrite
from the Reliable Write bit of extendedProperties. -
Initialize
propertiesObj.writableAuxiliaries
from the Writable Auxiliaries bit of extendedProperties.
-
-
Resolve promise with propertiesObj.
5.5. BluetoothRemoteGATTDescriptor
BluetoothRemoteGATTDescriptor
represents a GATT Descriptor, which
provides further information about a Characteristic’s value.
[Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTDescriptor
{ [SameObject] readonlyattributeBluetoothRemoteGATTCharacteristic characteristic; readonlyattributeUUID uuid; readonlyattributeDataView? value; Promise<DataView> readValue(); Promise<void> writeValue(BufferSourcevalue
); };
BluetoothRemoteGATTDescriptor
attributescharacteristic
is the GATT characteristic this descriptor belongs to.
uuid
is the UUID of the characteristic descriptor, e.g. '00002902-0000-1000-8000-00805f9b34fb'
for the Client Characteristic Configuration descriptor.
value
is the currently cached descriptor value. This value gets
updated when the value of the descriptor is read.
Instances of BluetoothRemoteGATTDescriptor
are created with the internal
slots described in the following table:
[[representedDescriptor]]
<always set in prose>
The Descriptor this object represents, or null
if the Descriptor
has been removed or otherwise invalidated.
BluetoothRemoteGATTDescriptor
representing a Descriptor descriptor,
the UA must return a new promise promise and run the following steps in parallel.
-
Let result be a new instance of
BluetoothRemoteGATTDescriptor
with its[[representedDescriptor]]
slot initialized to descriptor. -
Initialize
result.characteristic
from theBluetoothRemoteGATTCharacteristic
instance representing the Characteristic in which descriptor appears. -
Initialize
result.uuid
from the UUID of descriptor. -
Initialize
result.value
tonull
. The UA MAY initializeresult.value
to a newDataView
wrapping a newArrayBuffer
containing the most recently read value from descriptor if this value is available. -
Resolve promise with result.
readValue()
method, when invoked, MUST run the following steps:
-
If
this.uuid
is blocklisted for reads, return a promise rejected with aSecurityError
and abort these steps. -
If
this.characteristic.service.device.gatt.
isconnected
false
, return a promise rejected with aNetworkError
and abort these steps. -
Let descriptor be
this.
.[[representedDescriptor]]
-
If descriptor is
null
, return a promise rejected with anInvalidStateError
and abort these steps. -
Return a
this.characteristic.service.device.gatt
- connection-checking wrapper around a new promise promise and run the following steps in parallel:-
If the UA is currently using the Bluetooth system, it MAY reject promise with a
NetworkError
and abort these steps.Implementations may be able to avoid this
NetworkError
, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> -
Use either the Read Characteristic Descriptors or the Read Long Characteristic Descriptors sub-procedure to retrieve the value of descriptor. Handle errors as described in § 5.7 Error handling.
-
If the previous step returned an error, reject promise with that error and abort these steps.
-
Queue a task to perform the following steps:
-
If promise is not in
this.characteristic.service.device.gatt.
, reject promise with a[[activeAlgorithms]]
NetworkError
and abort these steps. -
Let buffer be an
ArrayBuffer
holding the retrieved value, and assignnew DataView(buffer)
tothis.value
. -
Resolve promise with
this.value
.
-
-
writeValue(value)
method, when invoked, MUST run the
following steps:
-
If
this.uuid
is blocklisted for writes, return a promise rejected with aSecurityError
and abort these steps. -
Let bytes be a copy of the bytes held by
value
. -
If bytes is more than 512 bytes long (the maximum length of an attribute value, per Long Attribute Values) return a promise rejected with an
InvalidModificationError
and abort these steps. -
If
this.characteristic.service.device.gatt.
isconnected
false
, return a promise rejected with aNetworkError
and abort these steps. -
Let descriptor be
this.
.[[representedDescriptor]]
-
If descriptor is
null
, return a promise rejected with anInvalidStateError
and abort these steps. -
Return a
this.characteristic.service.device.gatt
- connection-checking wrapper around a new promise promise and run the following steps in parallel.-
If the UA is currently using the Bluetooth system, it MAY reject promise with a
NetworkError
and abort these steps.Implementations may be able to avoid this
NetworkError
, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> -
Use either the Write Characteristic Descriptors or the Write Long Characteristic Descriptors sub-procedure to write bytes to descriptor. Handle errors as described in § 5.7 Error handling.
-
If the previous step returned an error, reject promise with that error and abort these steps.
-
Queue a task to perform the following steps:
-
If promise is not in
this.characteristic.service.device.gatt.
, reject promise with a[[activeAlgorithms]]
NetworkError
and abort these steps. -
Set
this.value
to a newDataView
wrapping a newArrayBuffer
containing bytes. -
Resolve promise with
undefined
.
-
-
5.6. Events
5.6.1. Bluetooth Tree
The Bluetooth tree is the name given to navigator.bluetooth
and objects implementing the BluetoothDevice
, BluetoothRemoteGATTService
, BluetoothRemoteGATTCharacteristic
, or BluetoothRemoteGATTDescriptor
interface participate in a tree.
-
The children of
navigator.bluetooth
are theBluetoothDevice
objects representing devices in theallowedDevices
list in"bluetooth"
's extra permission data fornavigator.bluetooth
's relevant settings object, in an unspecified order. -
The children of a
BluetoothDevice
are theBluetoothRemoteGATTService
objects representing Primary and Secondary Services on its GATT Server whose UUIDs are on the origin and device’sallowedServices
list. The order of the primary services MUST be consistent with the order returned by the Discover Primary Service by Service UUID procedure, but secondary services and primary services with different UUIDs may be in any order. -
The children of a
BluetoothRemoteGATTService
are theBluetoothRemoteGATTCharacteristic
objects representing its Characteristics. The order of the characteristics MUST be consistent with the order returned by the Discover Characteristics by UUID procedure, but characteristics with different UUIDs may be in any order. -
The children of a
BluetoothRemoteGATTCharacteristic
are theBluetoothRemoteGATTDescriptor
objects representing its Descriptors in the order returned by the Discover All Characteristic Descriptors procedure.
5.6.2. Event types
advertisementreceived
Fired on a BluetoothDevice
when an advertising event is received from
that device.
availabilitychanged
Fired on navigator.bluetooth
when the Bluetooth system as a whole
becomes available or unavailable to the UA.
characteristicvaluechanged
Fired on a BluetoothRemoteGATTCharacteristic
when its value changes,
either as a result of a read request , or a value change notification/indication.
gattserverdisconnected
Fired on a BluetoothDevice
when an active GATT connection is lost.
serviceadded
Fired on a new BluetoothRemoteGATTService
when it has been discovered on a remote
device, just after it is added to the Bluetooth tree.
servicechanged
Fired on a BluetoothRemoteGATTService
when its state changes.
This involves any characteristics and/or descriptors that get added or
removed from the service, as well as Service Changed indications from
the remote device.
serviceremoved
Fired on a BluetoothRemoteGATTService
when it has been removed from its
device, just before it is removed from the Bluetooth tree.
5.6.3. Responding to Disconnection
BluetoothDevice
deviceObj the
UA MUST queue a task on deviceObj’s relevant settings
object’s responsible event loop to perform the following steps:
-
If
deviceObj.
is not the same device as device, abort these steps.[[representedDevice]]
-
If
!deviceObj.gatt.
, abort these steps.connected
-
Clean up the disconnected device deviceObj.
-
Set
deviceObj.gatt.
toconnected
false
. -
Clear
deviceObj.gatt.
.[[activeAlgorithms]]
-
Let context be
deviceObj.
.[[context]]
-
Remove all entries from
context.
whose keys are inside[[attributeInstanceMap]]
deviceObj.
.[[representedDevice]]
-
For each
BluetoothRemoteGATTService
service in deviceObj’s realm, setservice.
to[[representedService]]
null
. -
For each
BluetoothRemoteGATTCharacteristic
characteristic in deviceObj’s realm, do the following sub-steps:-
Let notificationContexts be
characteristic.
’s active notification context set.[[representedCharacteristic]]
-
Remove context from notificationContexts.
-
If notificationContexts became empty and there is still an ATT Bearer to
deviceObj.
and characteristic has a Client Characteristic Configuration descriptor, the UA SHOULD use any of the Characteristic Descriptors procedures to clear the[[representedDevice]]
Notification
andIndication
bits in characteristic’s Client Characteristic Configuration descriptor. -
Set
characteristic.
to[[representedCharacteristic]]
null
.
-
-
For each
BluetoothRemoteGATTDescriptor
descriptor in deviceObj’s realm, setdescriptor.
to[[representedDescriptor]]
null
. -
Fire an event named
gattserverdisconnected
with itsbubbles
attribute initialized totrue
atdeviceObj
.Note: This event is not fired at theBluetoothRemoteGATTServer
.
5.6.4. Responding to Notifications and Indications
-
For each bluetoothGlobal in the Characteristic’s active notification context set, queue a task on the event loop of the script settings object of bluetoothGlobal to do the following sub-steps:
-
Let characteristicObject be the
BluetoothRemoteGATTCharacteristic
in the Bluetooth tree rooted at bluetoothGlobal that represents the Characteristic. -
If
characteristicObject .service.device.gatt.
isconnected
false
, abort these sub-steps. -
Set
characteristicObject.value
to a newDataView
wrapping a newArrayBuffer
holding the new value of the Characteristic. -
Fire an event named
characteristicvaluechanged
with itsbubbles
attribute initialized totrue
at characteristicObject.
-
5.6.5. Responding to Service Changes
-
Let removedAttributes be the list of attributes in the range indicated by the Service Changed characteristic that the UA had discovered before the Indication.
-
Use the Primary Service Discovery, Relationship Discovery, Characteristic Discovery, and Characteristic Descriptor Discovery procedures to re-discover attributes in the range indicated by the Service Changed characteristic. The UA MAY skip discovering all or part of the indicated range if it can prove that the results of that discovery could not affect the events fired below.
-
Let addedAttributes be the list of attributes discovered in the previous step.
-
If an attribute with the same definition (see the Service Interoperability Requirements), ignoring Characteristic and Descriptor values, appears in both removedAttributes and addedAttributes, remove it from both.
Given the following device states: State 1-
Service A
- Characteristic C: value
[1, 2, 3]
- Characteristic C: value
- Service B
-
Service A
- Characteristic C: value
[3, 2, 1]
- Characteristic C: value
- Service B
-
Service A
- Characteristic D: value
[3, 2, 1]
- Characteristic D: value
- Service B
-
Service A
- Characteristic C: value
[1, 2, 3]
- Characteristic C: value
-
Service B
- Include Service A
A transition from state 1 to 2 leaves service A with "the same definition, ignoring Characteristic and Descriptor values", which means it’s removed from both removedAttributes and addedAttributes, and it wouldn’t appear in any
servicechanged
events.A transition from state 1 to 3 leaves service A with a different definition, because a service definition includes its characteristic definitions, so it’s left in both removedAttributes and addedAttributes. Then in step 8, the service is moved to changedServices, which makes it cause a
servicechanged
event instead of both aserviceadded
andserviceremoved
. Step 9 also adds service A to changedServices because characteristic C was removed and characteristic D was added.A transition from state 1 to 4 is similar to the 1->3 transition. Service B is moved to changedServices in step 8, but no characteristics or descriptors have changed, so it’s not redundantly added in step 9.
-
Service A
-
Let invalidatedAttributes be the attributes in removedAttributes but not addedAttributes.
-
For each environment settings object settings in the UA, queue a task on its responsible event loop to do the following sub-steps:
-
For each
BluetoothRemoteGATTService
service whose relevant settings object is settings, ifservice.
is in invalidatedAttributes, set[[representedService]]
service.
to[[representedService]]
null
. -
For each
BluetoothRemoteGATTCharacteristic
characteristic whose relevant settings object is settings, ifcharacteristic.
is in invalidatedAttributes, set[[representedCharacteristic]]
characteristic.
to[[representedCharacteristic]]
null
. -
For each
BluetoothRemoteGATTDescriptor
descriptor whose relevant settings object is settings, ifdescriptor.
is in invalidatedAttributes, set[[representedDescriptor]]
descriptor.
to[[representedDescriptor]]
null
. -
Let global be settings’ global object.
-
Remove every entry from
global.navigator.bluetooth.
that represents an attribute that is in invalidatedAttributes.[[attributeInstanceMap]]
-
-
Let changedServices be a set of Services, initially empty.
-
If the same Service appears in both removedAttributes and addedAttributes, remove it from both, and add it to changedServices.
-
For each Characteristic and Descriptor in removedAttributes or addedAttributes, remove it from its original list, and add its parent Service to changedServices.
Note: After this point, removedAttributes and addedAttributes contain only Services. -
If a Service in addedAttributes would not have been returned from any previous call to
getPrimaryService
,getPrimaryServices
,getIncludedService
, orgetIncludedServices
if it had existed at the time of the call, the UA MAY remove the Service from addedAttributes. -
Let changedDevices be the set of Bluetooth devices that contain any Service in removedAttributes, addedAttributes, and changedServices.
-
For each
BluetoothDevice
deviceObj that is connected to a device in changedDevices, queue a task on its relevant global object’s responsible event loop to do the following steps:-
For each Service service in removedAttributes:
-
If
deviceObj.
is[[allowedServices]]
"all"
or contains the Service’s UUID, fire an event namedserviceremoved
with itsbubbles
attribute initialized totrue
at theBluetoothRemoteGATTService
representing the Service. -
Remove this
BluetoothRemoteGATTService
from the Bluetooth tree.
-
-
For each Service in addedAttributes, if
deviceObj.
is[[allowedServices]]
"all"
or contains the Service’s UUID, add theBluetoothRemoteGATTService
representing this Service to the Bluetooth tree and then fire an event namedserviceadded
with itsbubbles
attribute initialized totrue
at theBluetoothRemoteGATTService
. -
For each Service in changedServices, if
deviceObj.
is[[allowedServices]]
"all"
or contains the Service’s UUID, fire an event namedservicechanged
with itsbubbles
attribute initialized totrue
at theBluetoothRemoteGATTService
representing the Service.
-
5.6.6. IDL event handlers
[SecureContext]
interfacemixinCharacteristicEventHandlers
{
attributeEventHandler oncharacteristicvaluechanged;
};
oncharacteristicvaluechanged
is an Event handler IDL attribute for
the characteristicvaluechanged
event type.
[SecureContext]
interfacemixinBluetoothDeviceEventHandlers
{
attributeEventHandler onadvertisementreceived;
attributeEventHandler ongattserverdisconnected;
};
onadvertisementreceived
is an Event handler IDL attribute for the advertisementreceived
event
type.
ongattserverdisconnected
is an Event handler IDL attribute for the gattserverdisconnected
event type.
[SecureContext]
interfacemixinServiceEventHandlers
{
attributeEventHandler onserviceadded;
attributeEventHandler onservicechanged;
attributeEventHandler onserviceremoved;
};
onserviceadded
is an Event
handler IDL attribute for the serviceadded
event type.
onservicechanged
is an Event
handler IDL attribute for the servicechanged
event type.
onserviceremoved
is an Event
handler IDL attribute for the serviceremoved
event type.
5.7. Error handling
Error
Response
, the UA MUST perform the following steps:
-
If the procedure times out or the ATT Bearer (described in Profile Fundamentals) is absent or terminated for any reason, return a
NetworkError
from the step and abort these steps. -
Take the following actions depending on the
Error Code
:Invalid PDU
Invalid Offset
Attribute Not Found
Unsupported Group Type
These error codes indicate that something unexpected happened at the protocol layer, likely either due to a UA or device bug. Return aNotSupportedError
from the step.Invalid Handle
Return anInvalidStateError
from the step.Invalid Attribute Value Length
Return anInvalidModificationError
from the step.Attribute Not Long
If this error code is received without having used a "Long" sub-procedure, this may indicate a device bug. Return a
NotSupportedError
from the step.Otherwise, retry the step without using a "Long" sub-procedure. If this is impossible due to the length of the value being written, return an
InvalidModificationError
from the step.Insufficient Authentication
Insufficient Encryption
Insufficient Encryption Key Size
The UA SHOULD attempt to increase the security level of the connection. If this attempt fails or the UA doesn’t support any higher security, Return aSecurityError
from the step. Otherwise, retry the step at the new higher security level.Insufficient Authorization
Return aSecurityError
from the step.Application Error
If the GATT procedure was a Write, return anInvalidModificationError
from the step. Otherwise, return aNotSupportedError
from the step.Read Not Permitted
Write Not Permitted
Request Not Supported
Prepare Queue Full
Insufficient Resources
Unlikely Error
Anything else Return aNotSupportedError
from the step.
6. UUIDs
typedefDOMString UUID
;
A UUID string represents a 128-bit [RFC4122] UUID. A valid
UUID is a string that matches the [ECMAScript] regexp /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
.
That is, a valid UUID is lower-case and does not use the 16- or 32-bit
abbreviations defined by the Bluetooth standard. All UUIDs returned from
functions and attributes in this specification MUST be valid UUIDs. If a
function in this specification takes a parameter whose type is UUID or a
dictionary including a UUID attribute, and the argument passed in any UUID slot is not a valid UUID, the function MUST return a
promise rejected with a TypeError
and abort its other steps.
BluetoothUUID.canonicalUUID(alias)
function to map
a 16- or 32-bit Bluetooth UUID alias to its 128-bit form. 6.1. Standardized UUIDs
The Bluetooth SIG maintains a registry at [BLUETOOTH-ASSIGNED] of UUIDs that identify services, characteristics, descriptors, and other entities. This section provides a way for script to look up those UUIDs by name so they don’t need to be replicated in each application.
[Exposed=Window] interfaceBluetoothUUID
{ staticUUID getService((DOMString orunsignedlong)name
); staticUUID getCharacteristic((DOMString orunsignedlong)name
); staticUUID getDescriptor((DOMString orunsignedlong)name
); staticUUID canonicalUUID([EnforceRange] unsignedlongalias
); }; typedef (DOMString orunsignedlong) BluetoothServiceUUID; typedef (DOMString orunsignedlong) BluetoothCharacteristicUUID; typedef (DOMString orunsignedlong) BluetoothDescriptorUUID;
The static BluetoothUUID.
method, when invoked, MUST return the 128-bit UUID represented by the 16- or 32-bit UUID alias alias. canonicalUUID(alias)
00000000-0000-1000-8000-00805f9b34fb
" with the bits of the
alias. For example, canonicalUUID(0xDEADBEEF)
returns "deadbeef-0000-1000-8000-00805f9b34fb"
. BluetoothServiceUUID
represents 16- and 32-bit UUID
aliases, valid UUIDs, and names defined in [BLUETOOTH-ASSIGNED-SERVICES], or, equivalently, the values for which BluetoothUUID.getService()
does not throw an
exception.
BluetoothCharacteristicUUID
represents 16- and 32-bit UUID
aliases, valid UUIDs, and names defined in [BLUETOOTH-ASSIGNED-CHARACTERISTICS], or, equivalently, the values for which BluetoothUUID.getCharacteristic()
does
not throw an exception.
BluetoothDescriptorUUID
represents 16- and 32-bit UUID
aliases, valid UUIDs, and names defined in [BLUETOOTH-ASSIGNED-DESCRIPTORS], or, equivalently, the values for which BluetoothUUID.getDescriptor()
does not throw
an exception.
-
If name is an
unsigned long
, returnBluetoothUUID.canonicalUUID
(name) and abort these steps. -
If name is a valid UUID, return name and abort these steps.
-
If the string
prefix + "." + name
appears in assigned numbers table, let alias be its assigned number, and returnBluetoothUUID.canonicalUUID
(alias). -
Otherwise, throw a
TypeError
.
The static BluetoothUUID.
method, when invoked, MUST return ResolveUUIDName( getService(name)
name
, [BLUETOOTH-ASSIGNED-SERVICES], "org.bluetooth.service").
The static BluetoothUUID.
method, when invoked, MUST
return ResolveUUIDName( getCharacteristic(name)
name
, [BLUETOOTH-ASSIGNED-CHARACTERISTICS], "org.bluetooth.characteristic").
The static BluetoothUUID.
method, when invoked, MUST return ResolveUUIDName( getDescriptor(name)
name
, [BLUETOOTH-ASSIGNED-DESCRIPTORS], "org.bluetooth.descriptor").
BluetoothUUID.getService
(" cycling_power")
returns "00001818-0000-1000-8000-00805f9b34fb"
.
returns BluetoothUUID.getService
("00001801-0000-1000-8000-00805f9b34fb")"00001801-0000-1000-8000-00805f9b34fb"
.
throws a BluetoothUUID.getService
("unknown-service")TypeError
.
returns BluetoothUUID.getCharacteristic
("ieee_11073-20601_regulatory_certification_data_list
")"00002a2a-0000-1000-8000-00805f9b34fb"
.
returns BluetoothUUID.getDescriptor
("gatt.characteristic_presentation_format
")"00002904-0000-1000-8000-00805f9b34fb"
.
7. The GATT Blocklist
This specification relies on a blocklist file in the https://github.com/WebBluetoothCG/registries repository to restrict the set of GATT attributes a website can access.
-
Fetch url, and let contents be its body, decoded as UTF-8.
-
Let lines be contents split on
'\n'
. -
Let result be an empty map.
-
For each line in lines, do the following sub-steps:
-
If line is empty or its first character is
'#'
, continue to the next line. -
If line consists of just a valid UUID, let uuid be that UUID and let token be "
exclude
". -
If line consists of a valid UUID, a space (U+0020), and one of the tokens "
exclude-reads
" or "exclude-writes
", let uuid be that UUID and let token be that token. -
Otherwise, return an error and abort these steps.
-
If uuid is already in result, return an error and abort these steps.
-
Add a mapping in result from uuid to token.
-
-
Return result.
The GATT blocklist is the result of parsing the blocklist at https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt. The UA should re-fetch the blocklist periodically, but it’s unspecified how often.
A UUID is blocklisted if either the GATT blocklist’s
value is an error, or the UUID maps to "exclude
" in the GATT
blocklist.
A UUID is blocklisted for reads if either the GATT
blocklist’s value is an error, or the UUID maps to either
"exclude
" or "exclude-reads
" in the GATT
blocklist.
A UUID is blocklisted for writes if either the GATT
blocklist’s value is an error, or the UUID maps to either
"exclude
" or "exclude-writes
" in the GATT
blocklist.
8. Extensions to the Navigator Interface
[SecureContext]
partialinterfaceNavigator {
[SameObject]
readonlyattributeBluetooth bluetooth
;
};
9. Terminology and Conventions
This specification uses a few conventions and several terms from other specifications. This section lists those and links to their primary definitions.
When an algorithm in this specification uses a name defined in this or another
specification, the name MUST resolve to its initial value, ignoring any changes
that have been made to the name in the current execution environment. For
example, when the requestDevice()
algorithm says to call
,
this MUST apply the Array.prototype.map
.call(filter.services, BluetoothUUID.getService
)Array.prototype.map
algorithm defined in [ECMAScript] with filter.services
as its this
parameter
and the algorithm defined in § 6.1 Standardized UUIDs for BluetoothUUID.getService
as its callbackfn
parameter, regardless of any modifications that have
been made to window
, Array
, Array.prototype
, Array.prototype.map
, Function
, Function.prototype
, BluetoothUUID
, BluetoothUUID.getService
, or other
objects.
This specification uses a read-only type that is similar to WebIDL’s FrozenArray
.
-
A read only ArrayBuffer has
ArrayBuffer
's values and interface, except that attempting to write to its contents or transfer it has the same effect as trying to write to aFrozenArray
's contents. This applies toTypedArray
s andDataView
s wrapped around theArrayBuffer
too.
-
Architecture & Terminology Overview
-
General Description
- Overview of Bluetooth Low Energy Operation (defines advertising events)
-
Communication Topology and Operation
-
Operational Procedures and Modes
-
BR/EDR Procedures
-
Inquiry (Discovering) Procedure
- Extended Inquiry Response
-
Inquiry (Discovering) Procedure
-
BR/EDR Procedures
-
Operational Procedures and Modes
-
General Description
-
Core System Package [BR/EDR Controller volume]
-
Host Controller Interface Functional Specification
-
HCI Commands and Events
-
Informational Parameters
- Read BD_ADDR Command
-
Status Parameters
- Read RSSI Command
-
Informational Parameters
-
HCI Commands and Events
-
Host Controller Interface Functional Specification
-
Core System Package [Host volume]
-
Service Discovery Protocol (SDP) Specification
-
Overview
-
Searching for Services
- UUID (defines UUID aliases and the algorithm to compute the 128-bit UUID represented by a UUID alias)
-
Searching for Services
-
Overview
-
Generic Access Profile
-
Profile Overview
-
Profile Roles
-
Roles when Operating over an LE Physical Transport
- Broadcaster Role
- Observer Role
- Peripheral Role
- Central Role
-
Roles when Operating over an LE Physical Transport
-
Profile Roles
-
User Interface Aspects
-
Representation of Bluetooth Parameters
- Bluetooth Device Name (the user-friendly name)
-
Representation of Bluetooth Parameters
-
Idle Mode Procedures — BR/EDR Physical Transport
- Device Discovery Procedure
- BR/EDR Bonding Procedure
-
Operational Modes and Procedures — LE Physical Transport
-
Broadcast Mode and Observation Procedure
- Observation Procedure
-
Discovery Modes and Procedures
- General Discovery Procedure
- Name Discovery Procedure
- Connection Modes and Procedures
-
Bonding Modes and Procedures
- LE Bonding Procedure
-
Broadcast Mode and Observation Procedure
-
Security Aspects — LE Physical Transport
- Privacy Feature
-
Random Device Address
- Static Address
-
Private address
- Resolvable Private Address Resolution Procedure
- Advertising Data and Scan Response Data Format (defines AD structure)
-
Bluetooth Device Requirements
-
Bluetooth Device Address (defines BD_ADDR)
-
Bluetooth Device Address Types
- Public Bluetooth Address
-
Bluetooth Device Address Types
-
Bluetooth Device Address (defines BD_ADDR)
- Definitions (defines bond)
-
Profile Overview
-
Attribute Protocol (ATT)
-
Protocol Requirements
-
Basic Concepts
- Attribute Type
- Attribute Handle
- Long Attribute Values
-
Attribute Protocol Pdus
-
Error Handling
- Error Response
-
Error Handling
-
Basic Concepts
-
Protocol Requirements
-
Generic Attribute Profile (GATT)
-
Profile Overview
- Configurations and Roles (defines GATT Client and GATT Server)
- Profile Fundamentals, defines the ATT Bearer
-
Attribute Protocol
- Attribute Caching
-
GATT Profile Hierarchy
- Service
- Included Services
- Characteristic
-
Service Interoperability Requirements
- Service Definition
-
Characteristic Definition
-
Characteristic Declaration
- Characteristic Properties
-
Characteristic Descriptor Declarations
- Characteristic Extended Properties
- Client Characteristic Configuration
-
Characteristic Declaration
-
GATT Feature Requirements — defines the GATT procedures.
-
Server Configuration
- Exchange MTU
-
Primary Service Discovery
- Discover All Primary Services
- Discover Primary Service by Service UUID
-
Relationship Discovery
- Find Included Services
-
Characteristic Discovery
- Discover All Characteristics of a Service
- Discover Characteristics by UUID
-
Characteristic Descriptor Discovery
- Discover All Characteristic Descriptors
- Characteristic Value Read
-
Characteristic Value Write
- Write Without Response
- Write Characteristic Value
- Characteristic Value Notification
- Characteristic Value Indications
-
Characteristic Descriptors
- Read Characteristic Descriptors
- Read Long Characteristic Descriptors
- Write Characteristic Descriptors
- Write Long Characteristic Descriptors
- Procedure Timeouts
-
Server Configuration
-
GAP Interoperability Requirements
-
BR/EDR GAP Interoperability Requirements
- Connection Establishment
-
LE GAP Interoperability Requirements
- Connection Establishment
-
BR/EDR GAP Interoperability Requirements
-
Defined Generic Attribute Profile Service
- Service Changed
-
Profile Overview
-
Security Manager Specification
-
Security Manager
-
Security in Bluetooth Low Energy
- Definition of Keys and Values, defines the Identity Resolving Key (IRK)
-
Security in Bluetooth Low Energy
-
Security Manager
-
Service Discovery Protocol (SDP) Specification
-
Core System Package [Low Energy Controller volume]
-
Link Layer Specification
-
General Description
-
Device Address
- Public Device Address
-
Random Device Address
- Static Device Address
-
Device Address
-
Air Interface Protocol
-
Non-Connected States
-
Scanning State
- Passive Scanning
-
Scanning State
-
Non-Connected States
-
General Description
-
Link Layer Specification
-
Data Types Specification
-
Data Types Definitions and Formats
- Service UUID Data Type
- Local Name Data Type
- Flags Data Type (defines the Discoverable Mode flags)
- Manufacturer Specific Data
- TX Power Level
- Service Data
- Appearance
-
Data Types Definitions and Formats
Conformance
Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.
All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]
Examples in this specification are introduced with the words “for example”
or are set apart from the normative text with class="example"
, like this:
Informative notes begin with the word “Note”
and are set apart from the normative text with class="note"
, like this:
Note, this is an informative note.
Index
Terms defined by this specification
- abort all active watchAdvertisements, in §4.2
- abort watchAdvertisements, in §4.2
- acceptAllDevices
- [[activeAlgorithms]], in §5.2
- active notification context set, in §5.4
- add device to storage, in §3
- AD structure, in §9
- advertisementreceived, in §5.6.2
- Advertising Data, in §9
- advertising event, in §9
- advertising events, in §9
- AllowedBluetoothDevice, in §3.1
- allowedDevices, in §3.1
- [[allowedServices]], in §4.2
- allowedServices, in §3.1
- Appearance, in §9
- appearance
- ATT Bearer, in §9
- Attribute, in §5.1
- Attribute Caching, in §9
- Attribute Handle, in §9
- [[attributeInstanceMap]], in §3
- Attribute Type, in §9
- authenticatedSignedWrites, in §5.4.1
- availabilitychanged, in §5.6.2
- [[BackingMap]]
- BD_ADDR, in §9
- blocklisted, in §7
- blocklisted for reads, in §7
- blocklisted for writes, in §7
- "bluetooth", in §3.1
- Bluetooth, in §3
- bluetooth, in §8
- BluetoothAdvertisingEvent, in §4.2.3
- BluetoothAdvertisingEventInit, in §4.2.3
- BluetoothAdvertisingEvent(type, init), in §4.2.3
- Bluetooth cache, in §5.1.2
- BluetoothCharacteristicProperties, in §5.4.1
- BluetoothCharacteristicUUID, in §6.1
- BluetoothDataFilterInit, in §3
- BluetoothDescriptorUUID, in §6.1
- Bluetooth device, in §4.1
- BluetoothDevice, in §4.2
- BluetoothDeviceEventHandlers, in §5.6.6
- Bluetooth Device Name, in §9
- BluetoothLEScanFilterInit, in §3
- BluetoothManufacturerDataMap, in §4.2.3
- BluetoothPermissionDescriptor, in §3.1
- BluetoothPermissionResult, in §3.1
- BluetoothPermissionStorage, in §3.1
- BluetoothRemoteGATTCharacteristic, in §5.4
- BluetoothRemoteGATTDescriptor, in §5.5
- BluetoothRemoteGATTServer, in §5.2
- BluetoothRemoteGATTService, in §5.3
- BluetoothServiceDataMap, in §4.2.3
- BluetoothServiceUUID, in §6.1
- Bluetooth tree, in §5.6.1
- BluetoothUUID, in §6.1
- bond, in §9
- BR/EDR Bonding Procedure, in §9
- broadcast, in §5.4.1
- Broadcaster, in §9
- canonicalizing
- canonicalUUID(alias), in §6.1
- Central, in §9
- Characteristic, in §9
- characteristic, in §5.5
- Characteristic Descriptor Discovery, in §9
- Characteristic Descriptors, in §9
- Characteristic Discovery, in §9
- CharacteristicEventHandlers, in §5.6.6
- Characteristic Extended Properties, in §9
- Characteristic Properties, in §9
- characteristicvaluechanged, in §5.6.2
- Characteristic Value Indications, in §9
- Characteristic Value Notification, in §9
- Characteristic Value Read, in §9
- Characteristic Value Write, in §9
- clean up the disconnected device, in §5.6.3
- Client Characteristic Configuration, in §9
- connect(), in §5.2
- connected, in §5.2
- connection-checking wrapper, in §5.2
- constructor(type), in §3.2
- constructor(type, init), in §4.2.3
- constructor(type, initDict), in §3.2
- [[context]], in §4.2
- create a BluetoothCharacteristicProperties instance from the Characteristic, in §5.4.1
- create a BluetoothRemoteGATTCharacteristic representing, in §5.4
- create a BluetoothRemoteGATTDescriptor representing, in §5.5
- create a BluetoothRemoteGATTService representing, in §5.3
- dataPrefix, in §3
- Definition of Keys and Values, in §9
- Descriptor, in §9
- [[device]], in §3.1
- device
- Device Discovery Procedure, in §9
- deviceId
- [[deviceInstanceMap]], in §3
- devices, in §3.1
- disconnect(), in §5.2
- Discoverable Mode, in §9
- Discover All Characteristic Descriptors, in §9
- Discover Characteristics by UUID, in §9
- Discover Primary Service by Service UUID, in §9
- Error Response, in §9
- Exchange MTU, in §9
- Extended Inquiry Response, in §9
- filters
- fire an advertisementreceived event, in §4.2.3
- Flags Data Type, in §9
- GAP Interoperability Requirements, in §9
- garbage-collect the connection, in §5.2
- [[gatt]], in §4.2
- GATT, in §9
- gatt, in §4.2
- GATT blocklist, in §7
- GATT Client, in §9
- GATT procedure, in §9
- GATT procedures, in §9
- GATT Profile Hierarchy, in §9
- GATT Server, in §9
- gattserverdisconnected, in §5.6.2
- General Discovery Procedure, in §9
- Generic Attribute Profile, in §9
- getAvailability(), in §3.2
- getCharacteristic(characteristic), in §5.3
- getCharacteristic(name), in §6.1
- getCharacteristics(), in §5.3
- getCharacteristics(characteristic), in §5.3
- getDescriptor(descriptor), in §5.4
- getDescriptor(name), in §6.1
- getDescriptors(), in §5.4
- getDescriptors(descriptor), in §5.4
- getDevices(), in §3
- GetGATTChildren, in §5.1.3
- getIncludedServices(), in §5.3
- getIncludedService(service), in §5.3
- getIncludedServices(service), in §5.3
- getPrimaryServices(), in §5.2
- getPrimaryService(service), in §5.2
- getPrimaryServices(service), in §5.2
- getService(name), in §6.1
- get the BluetoothDevice representing, in §4.2
- id, in §4.2
- Identity Resolving Key, in §9
- Included Service, in §9
- indicate, in §5.4.1
- IRK, in §9
- isPrimary, in §5.3
- LE Bonding Procedure, in §9
- Local Name Data Type, in §9
- Long Attribute Values, in §9
- manufacturerData
- Manufacturer Specific Data, in §9
- mask, in §3
- match a filter, in §3
- matches, in §3
- matches a filter, in §3
- matches any filter, in §3
- mayUseGATT, in §3.1
- Name Discovery Procedure, in §9
- namePrefix, in §3
- notify, in §5.4.1
- Observation Procedure, in §9
- Observer, in §9
- onadvertisementreceived, in §5.6.6
- onavailabilitychanged, in §3
- oncharacteristicvaluechanged, in §5.6.6
- ongattserverdisconnected, in §5.6.6
- onserviceadded, in §5.6.6
- onservicechanged, in §5.6.6
- onserviceremoved, in §5.6.6
- optionalServices
- parsing the blocklist, in §7
- Passive Scanning, in §9
- Peripheral, in §9
- populate the Bluetooth cache, in §5.1.2
- Primary Service Discovery, in §9
- Privacy Feature, in §9
- Private address, in §9
- Procedure Timeouts, in §9
- procedure times out, in §9
- Profile Fundamentals, in §9
- properties, in §5.4
- Public Bluetooth Address, in §9
- Public Device Address, in §9
- query the Bluetooth cache, in §5.1.2
- query the "bluetooth" permission, in §3.1
- read, in §5.4.1
- Read BD_ADDR Command, in §9
- Read Characteristic Descriptors, in §9
- Read Long Characteristic Descriptors, in §9
- read only ArrayBuffer, in §9
- readValue()
- Received Signal Strength, in §9
- [[referringDevice]], in §3
- referringDevice, in §3
- Relationship Discovery, in §9
- reliableWrite, in §5.4.1
- Represented, in §5.1.2
- [[representedCharacteristic]], in §5.4
- [[representedDescriptor]], in §5.5
- [[representedDevice]], in §4.2
- [[representedService]], in §5.3
- request Bluetooth devices, in §3
- requestDevice(), in §3
- requestDevice(options), in §3
- RequestDeviceOptions, in §3
- request the "bluetooth" permission, in §3.1
- Resolvable Private Address Resolution Procedure, in §9
- ResolveUUIDName, in §6.1
- revoke Bluetooth access, in §3.1
- RSSI, in §9
- same attribute, in §5.1.4
- same Bluetooth device, in §4.1
- same device, in §4.1
- scan for devices, in §3
- Searching for Services, in §9
- Service, in §9
- service, in §5.4
- serviceadded, in §5.6.2
- Service Changed, in §9
- servicechanged, in §5.6.2
- Service Data, in §9
- serviceData
- Service Definition, in §9
- ServiceEventHandlers, in §5.6.6
- Service Interoperability Requirements, in §9
- serviceremoved, in §5.6.2
- services, in §3
- Service UUID Data Type, in §9
- Service UUIDs, in §9
- signal, in §4.2
- startNotifications(), in §5.4
- Static Address, in §9
- Static Device Address, in §9
- stopNotifications(), in §5.4
- supported physical transports, in §4.1
- the 128-bit UUID represented, in §9
- txPower
- TX Power Level, in §9
- UUID alias, in §9
- uuids
- valid UUID, in §6
- value
- ValueEvent, in §3.2
- ValueEventInit, in §3.2
- ValueEvent(type), in §3.2
- ValueEvent(type, initDict), in §3.2
- watchAdvertisements(), in §4.2
- watch advertisements manager, in §4.2
- watchAdvertisements(options), in §4.2
- WatchAdvertisementsOptions, in §4.2
- [[watchAdvertisementsState]], in §4.2
- watchingAdvertisements, in §4.2
- writableAuxiliaries, in §5.4.1
- write, in §5.4.1
- Write Characteristic Descriptors, in §9
- Write Characteristic Value, in §9
- WriteCharacteristicValue, in §5.4
- Write Long Characteristic Descriptors, in §9
- writeValue(value)
- writeValueWithoutResponse(value), in §5.4
- writeValueWithResponse(value), in §5.4
- Write Without Response, in §9
- writeWithoutResponse, in §5.4.1
Terms defined by reference
-
[BLUETOOTH-ASSIGNED] defines the following terms:
- org.bluetooth.characteristic.body_sensor_location
- org.bluetooth.characteristic.gap.appearance
- org.bluetooth.characteristic.heart_rate_control_point
- org.bluetooth.characteristic.heart_rate_measurement
- org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list
- org.bluetooth.descriptor.gatt.characteristic_presentation_format
- org.bluetooth.descriptor.gatt.client_characteristic_configuration
- org.bluetooth.service.cycling_power
- org.bluetooth.service.heart_rate
- shortened local name
-
[DOM] defines the following terms:
- AbortController
- AbortSignal
- Event
- EventInit
- EventTarget
- aborted flag
- bubbles
- children
- context object
- document
- fire an event
- isTrusted
- participate in a tree
-
[ECMAScript] defines the following terms:
- Array
- Array.prototype.map
- ArrayBuffer
- CanonicalNumericIndexString
- CreateDataProperty
- DataView
- IsInteger
- Promise
- TypeError
- TypedArray
- [[OwnPropertyKeys]]
- current realm
- internal slot
- realm
-
[ENCODING] defines the following terms:
- utf-8 decode without bom
- utf-8 encode
-
[fingerprinting-guidance] defines the following terms:
- fingerprinting surface
-
[HTML] defines the following terms:
- EventHandler
- Navigator
- browsing context
- current settings object
- enqueue the following steps
- environment settings object
- event handler idl attribute
- fully active
- global object (for environment settings object)
- in parallel
- initializing the document object
- navigate
- perform a microtask checkpoint
- queue a task
- relevant global object
- relevant settings object
- responsible document
- responsible event loop
- starting a new parallel queue
-
[INFRA] defines the following terms:
- abort when
- for each
- if aborted
-
[page-visibility] defines the following terms:
- document visibility state
-
[permissions] defines the following terms:
- "denied"
- PermissionDescriptor
- PermissionStatus
- allowed in non-secure contexts
- extra permission data
- extra permission data constraints
- extra permission data type
- permission descriptor type
- permission query algorithm
- permission result type
- permission revocation algorithm
- permission state
- powerful feature
- prompt the user to choose
- query(permissionDesc)
- state
-
[PERMISSIONS-REQUEST] defines the following terms:
- permission request algorithm
- request(permissionDesc)
-
[secure-contexts] defines the following terms:
- non-secure contexts
- secure contexts
-
[WebIDL] defines the following terms:
- AbortError
- BufferSource
- DOMException
- DOMString
- EnforceRange
- Exposed
- FrozenArray
- InvalidModificationError
- InvalidStateError
- NetworkError
- NotFoundError
- NotSupportedError
- SameObject
- SecureContext
- SecurityError
- UnknownError
- a copy of the bytes held
- a new promise
- a promise rejected with
- boolean
- converted to an ecmascript value
- converted to an idl value
- maplike
- object
- react
- reject
- resolve
- unsigned long
- unsigned short
- upon fulfillment
- waiting for all
References
Normative References
[BLUETOOTH-ASSIGNED] Assigned Numbers. Living Standard. URL: https://www.bluetooth.org/en-us/specification/assigned-numbers [BLUETOOTH-ASSIGNED-CHARACTERISTICS] Bluetooth GATT Specifications > Characteristics. Living Standard. URL: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx [BLUETOOTH-ASSIGNED-DESCRIPTORS] Bluetooth GATT Specifications > Descriptors. Living Standard. URL: https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorsHomePage.aspx [BLUETOOTH-ASSIGNED-SERVICES] Bluetooth GATT Specifications > Services. Living Standard. URL: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx [BLUETOOTH-SUPPLEMENT6] Supplement to the Bluetooth Core Specification Version 6. 14 July 2015. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=302735 [BLUETOOTH42] BLUETOOTH SPECIFICATION Version 4.2. 2 December 2014. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 [DOM] Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/ [ECMAScript] ECMAScript Language Specification. URL: https://tc39.es/ecma262/ [ENCODING] Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/ [FINGERPRINTING-GUIDANCE] Nick Doty. Mitigating Browser Fingerprinting in Web Specifications. 28 March 2019. NOTE. URL: https://www.w3.org/TR/fingerprinting-guidance/ [HTML] Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/ [INFRA] Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/ [PAGE-VISIBILITY] Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 29 October 2013. REC. URL: https://www.w3.org/TR/page-visibility/ [PERMISSIONS] Mounir Lamouri; Marcos Caceres; Jeffrey Yasskin. Permissions. 25 September 2017. WD. URL: https://www.w3.org/TR/permissions/ [PERMISSIONS-REQUEST] Requesting Permissions. cg-draft. URL: https://wicg.github.io/permissions-request/ [RFC2119] S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119 [RFC4122] P. Leach; M. Mealling; R. Salz. A Universally Unique IDentifier (UUID) URN Namespace. July 2005. Proposed Standard. URL: https://tools.ietf.org/html/rfc4122 [SECURE-CONTEXTS] Mike West. Secure Contexts. 15 September 2016. CR. URL: https://www.w3.org/TR/secure-contexts/ [WebIDL] Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/Informative References
[CSP3] Mike West. Content Security Policy Level 3. 15 October 2018. WD. URL: https://www.w3.org/TR/CSP3/IDL Index
dictionaryBluetoothDataFilterInit
{ BufferSourcedataPrefix
; BufferSourcemask
; }; dictionaryBluetoothLEScanFilterInit
{ sequence<BluetoothServiceUUID> services; DOMString name; DOMString namePrefix; // Maps unsigned shorts to BluetoothDataFilters. object manufacturerData; // Maps BluetoothServiceUUIDs to BluetoothDataFilters. object serviceData; }; dictionaryRequestDeviceOptions
{ sequence<BluetoothLEScanFilterInit> filters; sequence<BluetoothServiceUUID> optionalServices = []; boolean acceptAllDevices = false; }; [Exposed=Window, SecureContext] interfaceBluetooth
: EventTarget { Promise<boolean> getAvailability(); attributeEventHandleronavailabilitychanged
; [SameObject] readonlyattributeBluetoothDevice? referringDevice; Promise<sequence<BluetoothDevice>> getDevices(); Promise<BluetoothDevice> requestDevice(optionalRequestDeviceOptionsoptions
= {}); }; Bluetooth includesBluetoothDeviceEventHandlers; Bluetooth includesCharacteristicEventHandlers; Bluetooth includesServiceEventHandlers; dictionaryBluetoothPermissionDescriptor
: PermissionDescriptor { DOMStringdeviceId
; // These match RequestDeviceOptions. sequence<BluetoothLEScanFilterInit>filters
; sequence<BluetoothServiceUUID>optionalServices
= []; booleanacceptAllDevices
= false; }; dictionaryAllowedBluetoothDevice
{ requiredDOMStringdeviceId
; requiredbooleanmayUseGATT
; // An allowedServices of "all" means all services are allowed. required (DOMString orsequence<UUID>)allowedServices
; }; dictionaryBluetoothPermissionStorage
{ requiredsequence<AllowedBluetoothDevice>allowedDevices
; }; [Exposed=Window] interfaceBluetoothPermissionResult
: PermissionStatus { attributeFrozenArray<BluetoothDevice>devices
; }; [ Exposed=Window, SecureContext ] interfaceValueEvent
: Event {constructor
(DOMStringtype
, optionalValueEventInitinitDict
= {}); readonlyattributeanyvalue; }; dictionaryValueEventInit
: EventInit { anyvalue
= null; }; [Exposed=Window, SecureContext] interfaceBluetoothDevice
: EventTarget { readonlyattributeDOMString id; readonlyattributeDOMString? name; readonlyattributeBluetoothRemoteGATTServer? gatt; Promise<void> watchAdvertisements( optionalWatchAdvertisementsOptionsoptions
= {}); readonlyattributeboolean watchingAdvertisements; }; BluetoothDevice includesBluetoothDeviceEventHandlers; BluetoothDevice includesCharacteristicEventHandlers; BluetoothDevice includesServiceEventHandlers; dictionaryWatchAdvertisementsOptions
{ AbortSignalsignal
; }; [Exposed=Window, SecureContext] interfaceBluetoothManufacturerDataMap { readonlymaplike<unsignedshort, DataView>; }; [Exposed=Window, SecureContext] interfaceBluetoothServiceDataMap { readonlymaplike<UUID, DataView>; }; [ Exposed=Window, SecureContext ] interfaceBluetoothAdvertisingEvent
: Event { constructor(DOMStringtype
, BluetoothAdvertisingEventInitinit
); [SameObject] readonlyattributeBluetoothDevice device; readonlyattributeFrozenArray<UUID> uuids; readonlyattributeDOMString? name; readonlyattributeunsignedshort? appearance; readonlyattributebyte? txPower; readonlyattributebyte? rssi; [SameObject] readonlyattributeBluetoothManufacturerDataMap manufacturerData; [SameObject] readonlyattributeBluetoothServiceDataMap serviceData; }; dictionaryBluetoothAdvertisingEventInit
: EventInit { requiredBluetoothDevicedevice
; sequence<(DOMString orunsignedlong)>uuids
; DOMStringname
; unsignedshortappearance
; bytetxPower
; byterssi
; BluetoothManufacturerDataMapmanufacturerData
; BluetoothServiceDataMapserviceData
; }; [Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTServer
{ [SameObject] readonlyattributeBluetoothDevice device; readonlyattributeboolean connected; Promise<BluetoothRemoteGATTServer> connect(); voiddisconnect(); Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUIDservice
); Promise<sequence<BluetoothRemoteGATTService>> getPrimaryServices(optionalBluetoothServiceUUIDservice
); }; [Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTService
: EventTarget { [SameObject] readonlyattributeBluetoothDevice device; readonlyattributeUUID uuid; readonlyattributeboolean isPrimary; Promise<BluetoothRemoteGATTCharacteristic> getCharacteristic(BluetoothCharacteristicUUIDcharacteristic
); Promise<sequence<BluetoothRemoteGATTCharacteristic>> getCharacteristics(optionalBluetoothCharacteristicUUIDcharacteristic
); Promise<BluetoothRemoteGATTService> getIncludedService(BluetoothServiceUUIDservice
); Promise<sequence<BluetoothRemoteGATTService>> getIncludedServices(optionalBluetoothServiceUUIDservice
); }; BluetoothRemoteGATTService includesCharacteristicEventHandlers; BluetoothRemoteGATTService includesServiceEventHandlers; [Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTCharacteristic
: EventTarget { [SameObject] readonlyattributeBluetoothRemoteGATTService service; readonlyattributeUUID uuid; readonlyattributeBluetoothCharacteristicProperties properties; readonlyattributeDataView? value; Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUIDdescriptor
); Promise<sequence<BluetoothRemoteGATTDescriptor>> getDescriptors(optionalBluetoothDescriptorUUIDdescriptor
); Promise<DataView> readValue(); Promise<void> writeValue(BufferSourcevalue
); Promise<void> writeValueWithResponse(BufferSourcevalue
); Promise<void> writeValueWithoutResponse(BufferSourcevalue
); Promise<BluetoothRemoteGATTCharacteristic> startNotifications(); Promise<BluetoothRemoteGATTCharacteristic> stopNotifications(); }; BluetoothRemoteGATTCharacteristic includesCharacteristicEventHandlers; [Exposed=Window, SecureContext] interfaceBluetoothCharacteristicProperties
{ readonlyattributebooleanbroadcast
; readonlyattributebooleanread
; readonlyattributebooleanwriteWithoutResponse
; readonlyattributebooleanwrite
; readonlyattributebooleannotify
; readonlyattributebooleanindicate
; readonlyattributebooleanauthenticatedSignedWrites
; readonlyattributebooleanreliableWrite
; readonlyattributebooleanwritableAuxiliaries
; }; [Exposed=Window, SecureContext] interfaceBluetoothRemoteGATTDescriptor
{ [SameObject] readonlyattributeBluetoothRemoteGATTCharacteristic characteristic; readonlyattributeUUID uuid; readonlyattributeDataView? value; Promise<DataView> readValue(); Promise<void> writeValue(BufferSourcevalue
); }; [SecureContext] interfacemixinCharacteristicEventHandlers
{ attributeEventHandler oncharacteristicvaluechanged; }; [SecureContext] interfacemixinBluetoothDeviceEventHandlers
{ attributeEventHandler onadvertisementreceived; attributeEventHandler ongattserverdisconnected; }; [SecureContext] interfacemixinServiceEventHandlers
{ attributeEventHandler onserviceadded; attributeEventHandler onservicechanged; attributeEventHandler onserviceremoved; }; typedefDOMStringUUID
; [Exposed=Window] interfaceBluetoothUUID
{ staticUUID getService((DOMString orunsignedlong)name
); staticUUID getCharacteristic((DOMString orunsignedlong)name
); staticUUID getDescriptor((DOMString orunsignedlong)name
); staticUUID canonicalUUID([EnforceRange] unsignedlongalias
); }; typedef (DOMString orunsignedlong) BluetoothServiceUUID; typedef (DOMString orunsignedlong) BluetoothCharacteristicUUID; typedef (DOMString orunsignedlong) BluetoothDescriptorUUID; [SecureContext] partialinterfaceNavigator { [SameObject] readonlyattributeBluetoothbluetooth
; };
Issues Index
NetworkError
,
but for now sites need to serialize their use of this API
and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> ↵ NetworkError
,
but for now sites need to serialize their use of this API and/or give
the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> ↵ NetworkError
,
but for now sites need to serialize their use of this API
and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> ↵ NetworkError
, but
for now sites need to serialize their use of this API and/or give the user a
way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> ↵ NetworkError
,
but for now sites need to serialize their use of this API
and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> ↵ NetworkError
,
but for now sites need to serialize their use of this API
and/or give the user a way to retry failed operations. <https://github.com/WebBluetoothCG/web-bluetooth/issues/188> ↵ Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK