1. 简介
本节为非规范性内容。
蓝牙是一种用于设备间短距离无线通信的标准。蓝牙“经典版”(BR/EDR) 定义了一套二进制协议,支持最高约24Mbps的速度。蓝牙4.0引入了一种新的“低功耗”模式,被称为“蓝牙智能”( BLE,或简称LE),其速率限制为约1Mbps,但可以让设备大部分时间关闭其发射器。BLE 主要通过 通用属性规范(GATT) 以键/值对的方式提供大多数功能。
BLE 定义了多种设备角色。广播者和 观察者角色分别用于仅发射和仅接收的应用。 在从设备(Peripheral)角色下的设备可以被连接,而在 主设备(Central)角色下的设备可以连接到 从设备。
作为从设备或主设备角色的设备可以承载 GATT 服务器,其暴露一个 服务、 特征和 描述符的层级结构。更多关于该层级的信息见 § 6.1 GATT 信息模型。虽然该协议为BLE传输设计,GATT协议也可以运行在BR/EDR传输上。
本规范的第一个版本允许运行在UA中的网页以主设备角色,通过BR/EDR或LE连接, 连接到GATT 服务器。尽管本规范引用了 [BLUETOOTH42] 规范,它也兼容仅实现蓝牙4.0或4.1的设备间通信。
1.1. 示例
...(代码略,保持原样)...
parseHeartRate()会基于
heart_rate_measurement 文档
来读取存在于
DataView
类型的
BluetoothRemoteGATTCharacteristic
的
value
字段的数据。
...(代码略,保持原样)...
onHeartRateChanged() 可能会打印如下对象:
{ heartRate: 70 , contactDetected: true , energyExpended: 750 , // 意味着750kJ。 rrIntervals: [ 890 , 870 ] // 即.87s和.85s。 }
如果心率传感器报告了 energyExpended 字段,Web应用可以通过写入
heart_rate_control_point
特征,将其值重置为 0:
...(代码略,保持原样)...
2. 安全性注意事项
参见 § 3 隐私注意事项 小节。 [Issue #575]
3. 隐私注意事项
3.1. 设备访问权限很强
当网站使用 requestDevice()
请求设备访问权限时,它将能访问调用中所有提及的 GATT 服务。
UA 在询问用户要将哪些设备授权给网站前,必须告知用户这些服务赋予了网页哪些能力。如果列表中有任何服务 UA 不识别,UA 必须假定网站可完全控制设备,并提醒用户相关风险。
UA 还应允许用户检查哪些网站能访问哪些设备,并撤销这些配对关系。
UA 不得允许用户将整个设备类别配对给一个网站。有可能构造出每台设备都提供相同标识信息的设备类别。UA 不要求检测这类伪造,可以允许用户将此类伪设备配对给网站。
为确保只有经用户批准的实体真正获得访问权限,本规范要求只有安全上下文可访问蓝牙设备。
3.2. 可信服务器有可能传递恶意代码
本节为非规范性内容。
即使用户信任某个源,该源的服务器或开发者也可能被攻破,网站还可能存在XSS漏洞。这两种情况都可能导致用户授权恶意代码访问宝贵设备。源站应定义内容安全策略([CSP3]),以降低XSS风险,但这对攻破服务器或开发者无效。
通过§ 4.1 权限API集成,允许页面重载后恢复已授权设备,这增加了风险。攻击者无需在网站被攻破时获授权,只要用户再次访问即可利用已授权设备。但另一方面,页面重载下保留设备访问权限,可以减少权限提示,使用户更可能关注每一次出现的提示。
3.3. 针对设备的攻击
本节为非规范性内容。
网站的通信可能会破坏部分设备的安全模型,这些设备假设只会收到可信远端设备操作系统发出的信息。典型如人机接口设备,允许网页通信等于允许网站窃取键盘输入。本规范通过GATT封锁列表限制此类易受攻击的服务、特征和描述符,防止网页滥用。
我们预计许多设备容易因无线信号收到异常数据而遭攻击。以往需一台台设备被攻破,而本API可能导致大规模攻击。本规范通过如下措施增加攻击难度:
-
只允许配对单一设备,而不是配对设备类别,每次必须用户操作才可被利用。
-
限定访问GATT,而非通用字节流,阻断了恶意网页访问大部分设备解析器。
-
本API绝不会暴露蓝牙地址、数据签名密钥或加密密钥(密钥和值的定义)给网页。这减少网站预测将被发送的无线数据位的可能性,阻断 包中包注入攻击; 但仅加密链接有效,并非所有 BLE 设备都要求支持加密。
-
与§ 11.1 权限策略集成,为蓝牙访问增加保护需顶层文档明确允许跨源 iframe 使用这些API方法。
UA 还可采取进一步措施保护用户:
-
网络服务可以收集恶意网站及易受攻击设备的列表。UA 可拒绝恶意网址访问任何设备,也可拒绝任何网址访问高风险设备。
3.4. 蓝牙设备标识符
本节为非规范性内容。
每个蓝牙BR/EDR设备有唯一的48位MAC地址,称为BD_ADDR。每个蓝牙LE设备至少有一个公用设备地址 或 静态设备地址。公用设备地址 是 MAC 地址。静态设备地址可在每次重启时刷新。BR/EDR/LE 设备的BD_ADDR 与公用设备地址 相同(见Read BD_ADDR 指令)。
LE设备还可能有唯一的128位身份解析密钥(IRK),会在配对过程中传给可信设备。为避免泄露持久标识,LE设备可以使用随机 可解析/不可解析私有地址 进行扫描与广播,而不是用静态或公用地址。这些私有地址会定期(大约每15分钟)刷新,但经过配对的设备可用存储的 IRK 检查任一可解析私有地址是否匹配,方法见可解析私有地址解析过程。
每个蓝牙设备还有一个可读的人类友好蓝牙设备名。这不是唯一的,但根据设备类型有可能在实际中唯一。
3.4.1. 远程蓝牙设备的标识符
本节为非规范性内容。
一旦网页获取了持久设备ID,就能通过汇总附近设备目录大规模推断用户位置,还可分析某用户通过同一蓝牙设备配对多个网站的行为。另一方面,许多GATT服务可用于设备指纹,设备本身也能轻松暴露自定义GATT服务放大这一能力。
本规范建议 UA 对同一设备分别为用户未允许脚本发现是否为同一设备的情况生成不同ID,使网站难以滥用设备地址。设备制造商依旧可通过特殊方式追踪用户,但需花费额外精力。
3.4.2. UA 的蓝牙地址
本节为非规范性内容。
在BR/EDR模式,或LE模式下主动扫描且未启用隐私功能时,UA 会将其持久ID广播给附近所有蓝牙设备。这使得恶意设备可以分布到各区域追踪该UA。截至2014年8月,基本没有平台记录已实现 隐私功能,因此尽管本规范推荐,实际应用较少。规范还要求用户手势才可触发网站扫描,降低了扫描频率,但更多平台支持隐私功能会更理想。
3.5. 暴露蓝牙可用性
本节为非规范性内容。
navigator.bluetooth.
暴露了用户系统是否有蓝牙射频模块(无论其是否已通电)。如果用户配置了 UA 阻止网页蓝牙,则可用性也受影响。有些用户可能认为这属于隐私,但泄漏此信息可能带来的损害有限。该信息会略微提高UA的
指纹表面。该函数返回getAvailability()Promise,
因此UA可选择让用户指定返回值,但我们认为风险增量极小,UA 一般不会提示用户。
4. 设备发现
dictionary {BluetoothDataFilterInit BufferSource ;dataPrefix BufferSource ; };mask dictionary :BluetoothManufacturerDataFilterInit BluetoothDataFilterInit {required [EnforceRange ]unsigned short ; };companyIdentifier dictionary :BluetoothServiceDataFilterInit BluetoothDataFilterInit {required BluetoothServiceUUID ; };service dictionary {BluetoothLEScanFilterInit sequence <BluetoothServiceUUID >services ;DOMString name ;DOMString namePrefix ;sequence <BluetoothManufacturerDataFilterInit >manufacturerData ;sequence <BluetoothServiceDataFilterInit >serviceData ; };dictionary {RequestDeviceOptions sequence <BluetoothLEScanFilterInit >filters ;sequence <BluetoothLEScanFilterInit >exclusionFilters ;sequence <BluetoothServiceUUID >optionalServices = [];sequence <unsigned short >optionalManufacturerData = [];boolean acceptAllDevices =false ; }; [Exposed =Window ,SecureContext ]interface :Bluetooth EventTarget {Promise <boolean >getAvailability ();attribute EventHandler ; [onavailabilitychanged SameObject ]readonly attribute BluetoothDevice ?referringDevice ;Promise <sequence <BluetoothDevice >>getDevices ();Promise <BluetoothDevice >requestDevice (optional RequestDeviceOptions = {}); };options Bluetooth includes BluetoothDeviceEventHandlers ;Bluetooth includes CharacteristicEventHandlers ;Bluetooth includes ServiceEventHandlers ;
本规范中定义的方法通常异步完成,会在Bluetooth 任务源上排队执行工作。
Bluetooth
成员getAvailability()
会告知页面是否完全可用蓝牙功能。通过软件被禁用的适配器也应计为“可用”。可用性的变化(例如用户物理连接或拔下适配器)会通过
availabilitychanged
事件报告。
referringDevice
会提供用户打开此页面所用设备(若有)的访问。例如,Eddystone
信标可能广播一个 URL,UA 允许用户打开它。代表该信标的
BluetoothDevice
将可通过
navigator.bluetooth.
获取。
referringDevice
getDevices()
使页面能够检索用户已授予访问权限的蓝牙设备。
requestDevice(options)
会请求用户授予此源对一个设备的访问权限,该设备需要匹配任一筛选器于
options.
中,但不能匹配任一筛选器
于
filtersoptions.。
要匹配筛选器,设备需:
exclusionFilters
-
若该成员存在,支持
services列表中的所有 GATT 服务 UUID; -
若该成员存在,设备名等于
name; -
若该成员存在,设备名以
namePrefix开头; -
若该成员存在,广播的厂商特定数据需匹配
manufacturerData中的所有值; -
若该成员存在,广播的服务数据需匹配
serviceData中的所有值。
厂商特定数据和服务数据都将键映射到字节数组。BluetoothDataFilterInit
对这些数组进行过滤。若存在一个prefix使得
prefix &
等于
mask,则数组匹配。
dataPrefix
& mask
注意:如果设备在连接时显著改变其行为,例如不再广播其识别性的厂商数据而是让客户端发现一些识别性的 GATT 服务,则网站可能需要同时包含两种行为的筛选器。
在少数情况下,设备可能不会广播足够的区分信息以让网站筛掉不感兴趣的设备。这种情况下,网站可以将 acceptAllDevices 设为
true 并省略
filters
和 exclusionFilters。
这将把选择正确设备的负担完全交给网站用户。如果网站使用了
acceptAllDevices,
则只能使用列在 optionalServices
中的服务。
在用户选择与此源配对的设备后,该源可以访问任一服务,其 UUID 出现在任意元素的
services
列表中,或出现在
options.filters 中,或出现在
options.
中。
源还可以访问来自设备广播数据中由
optionalServicesoptions.
定义的厂商代码的任一厂商数据。
optionalManufacturerData
这意味着如果开发者仅按名称筛选,则必须使用
optionalServices
才能访问任一服务。
| 设备 | 已广播的服务 |
|---|---|
| D1 | A, B, C, D |
| D2 | A, B, E |
| D3 | C, D |
| D4 | E |
| D5 | <none> |
如果网站调用
navigator. bluetooth. requestDevice({ filters: [ { services: [ A, B]} ] });
用户会看到包含设备 D1 和 D2 的对话框。若用户选择 D1,网站将无法访问服务 C 或 D。若选择 D2,网站将无法访问服务 E。
另一方面,如果网站调用
navigator. bluetooth. requestDevice({ filters: [ { services: [ A, B]}, { services: [ C, D]} ] });
对话框将包含设备 D1、D2 和 D3;如果用户选择 D1,网站将能够访问服务 A、B、C 和 D。
如果网站随后调用
navigator. bluetooth. getDevices();
返回的 Promise
将解析为包含设备 D1 的数组,网站将能访问服务 A、B、C 和 D。
optionalServices 列表不会向用户所见对话框添加任何设备,但会影响用户所选设备上网站可用的服务。
navigator. bluetooth. requestDevice({ filters: [ { services: [ A, B]} ], optionalServices: [ E] });
显示包含 D1 和 D2 的对话框,但不包含 D4,因为 D4 不包含所需服务。若用户选择 D2,与第一个示例不同,网站将能访问服务 A、B 和 E。
如果网站再次调用
navigator. bluetooth. getDevices();
则返回的 Promise
会解析为包含设备 D1 和 D2 的数组。D1 上可访问 A、B、C、D 服务,而 D2 上可访问 A、B、E 服务。
若在用户授予访问后设备发生变化,允许的服务仍然适用。例如,如果用户在先前的 requestDevice() 调用中选择了 D1,而 D1 之后新增了 E 服务,将触发
serviceadded
事件,网页将能够访问服务 E。
| 设备 | 广播的设备名 |
|---|---|
| D1 | First De… |
| D2 | <none> |
| D3 | Device Third |
| D4 | Device Fourth |
| D5 | Unique Name |
下表展示了向 navigator.bluetooth.requestDevice({filters: filters}) 传入若干
filters 值时,用户可在其间进行选择的设备:
| filters | 设备 | 说明 |
|---|---|---|
| D5 | |
| D3, D4 | |
| <none> | D1 仅广播了其名称的前缀,因此尝试匹配完整名称会失败。 |
| D1, D5 | |
| D3, D5 |
下表展示了向 navigator.bluetooth.requestDevice({filters: filters,
exclusionFilters: exclusionFilters}) 传入若干
filters 与 exclusionFilters 值时,用户可在其间进行选择的设备:
| filters | exclusionFilters | 设备 |
|---|---|---|
|
| D4 |
|
| D3 |
|
| D3 |
| 设备 | 厂商数据 | 服务数据 |
|---|---|---|
| D1 | 17: 01 02 03 | |
| D2 | A: 01 02 03 |
下表展示了向 navigator.bluetooth.requestDevice({filters: filters}) 传入若干
filters 值时,用户可在其间进行选择的设备:
| filters | 设备 |
|---|---|
| D1 |
| D2 |
| D1, D2 |
| <none> |
| D1 |
| <none> |
| D1 |
| D1 |
| <none> |
TypeError。
若要接受所有设备,请改用 acceptAllDevices。
| 调用 | 说明 |
|---|---|
requestDevice | 无效:省略的筛选器列表不接受任何设备。 |
requestDevice | 无效:空的筛选器列表不接受任何设备。 |
requestDevice | 无效:空的筛选器会接受所有设备,因此也不允许。 |
requestDevice |
有效:通过 acceptAllDevices
明确接受所有设备。
|
requestDevice | 无效:acceptAllDevices
将覆盖任何 filters。
|
requestDevice | 无效:acceptAllDevices
将覆盖任何 exclusionFilters。
|
requestDevice | 无效:exclusionFilters
需要搭配 filters。
|
requestDevice |
无效:exclusionFilters
必须为非空才能排除设备。
|
requestDevice |
无效:如果提供,namePrefix 必须为非空以筛选设备。
|
requestDevice |
无效:若提供,manufacturerData
必须为非空才能筛选设备。
|
requestDevice |
无效:若提供,serviceData
必须为非空才能筛选设备。
|
| 内部槽位 | 初始值 | 描述(非规范性) |
|---|---|---|
[[deviceInstanceMap]]
|
一个从蓝牙设备
到
实例的空映射。
|
确保在单个全局对象内,每个蓝牙设备仅由一个 BluetoothDevice
实例表示。
|
[[attributeInstanceMap]]
|
一个从蓝牙缓存条目到 Promise
的空映射。
|
这些 Promise
将解析为 BluetoothRemoteGATTService、
BluetoothRemoteGATTCharacteristic
或
BluetoothRemoteGATTDescriptor
实例。
|
[[referringDevice]]
|
null
|
若 Document 是由该设备打开的,则在初始化 Document 对象时,设置为一个
BluetoothDevice。
|
navigator.bluetooth.referringDevice
必须返回
[[referringDevice]]。
如果发生这种情况,则作为初始化 Document 对象的一部分,UA 必须执行以下步骤:
-
令 referringDevice 为导致该次导航的设备。
-
获取表示
BluetoothDevice的对象 referringDevice,位于navigator.bluetooth内,并令 referringDeviceObj 为结果。 -
如果上一步抛出了异常,放弃这些步骤。
Note: 这意味着 UA 并未推断用户意图授予当前领域访问 referringDevice 的权限。例如,用户可能已全局拒绝 GATT 访问。 -
将
navigator.bluetooth.设为 referringDeviceObj。[[referringDevice]]
match,则称其匹配某筛选器 filter:
-
如果
filter.存在,则若 device 的蓝牙设备名不完整或不等于namefilter.name,返回mismatch。 -
如果
filter.存在,则若 device 的蓝牙设备名不存在或不以namePrefixfilter.namePrefix开头,返回mismatch。 -
对于
filter.中的每个 uuid,若 UA 未接收到广告数据、扩展查询响应,或指示设备支持 UUID 为 uuid 的主(非包含)服务的服务发现响应,则返回servicesmismatch。 -
对于
filter["中的每个 manufacturerData,若 device 未广播厂商特定数据,其公司标识符等于manufacturerData"]manufacturerData[",且数据匹配companyIdentifier"]manufacturerData,则返回mismatch。 -
对于
filter["中的每个 serviceData,若 device 未广播服务数据,其 128 位形式的 UUID 等于serviceData"]serviceData[", 且数据匹配service"]serviceData,则返回mismatch。 -
返回
match。
match,则其匹配
一个 BluetoothDataFilterInit
filter:
-
令 expectedPrefix 为 由字节构成的拷贝,其来源为
filter.。dataPrefix -
如果 data 的字节数少于 expectedPrefix,返回
mismatch。 -
对于 mask 中的每个
1位,若 data 中对应位不等于 expectedPrefix 中对应位,返回mismatch。 -
返回
match。
BluetoothDataFilterInit
filter1 依据以下步骤返回 true,则其为另一个 BluetoothDataFilterInit
filter2 的严格子集:
-
如果 filter1 的长度小于 filter2 的长度,返回
false。 -
令 byteIndex 为
0。 -
当 byteIndex 小于 filter2 的长度时,执行以下子步骤:
-
如果
filter1.不等于 filter2.mask[byteIndex] & filter2.mask[byteIndex]mask[byteIndex],返回false。 -
如果
filter1.不等于dataPrefix[byteIndex] & filter2.mask[byteIndex]filter2.,返回dataPrefix[byteIndex] & filter2.mask[byteIndex]false。 -
将 byteIndex 设为
byteIndex + 1。
-
-
返回
true。
getDevices()
方法并给定一个 BluetoothPermissionStorage
storage 时,必须执行以下步骤:
-
如果 global 的关联的 Document未被允许使用名为 "bluetooth" 的策略控制特性,则返回以
SecurityError拒绝的 promise。 -
令 promise 为一个新的 promise。
-
并行执行以下步骤:
-
令 devices 为新的空
Array。 -
对于
storage.中的每个 allowedDevice,将表示 allowedDevice@allowedDevices[[device]]的BluetoothDevice对象添加到 devices。 -
针对给定的 global 在Bluetooth 任务源上排队一个全局任务,用 devices 解析 promise。
Note: devices 中的BluetoothDevice可能不在蓝牙射频范围内。对于 devices 中的某个 device,可使用watchAdvertisements()方法在 device 处于范围内并广播广告包时进行观察。当在某个 device 上触发advertisementreceived事件 event 时,可能表示它距离足够近,可以通过调用event.device.gatt.建立连接。connect() -
-
返回 promise。
requestDevice(options)
方法时,必须执行以下步骤:
-
如果
options.存在而exclusionFiltersoptions.不存在,返回以filtersTypeError拒绝的 promise。 -
如果
options.存在且filtersoptions.为acceptAllDevicestrue,或options.不存在且filtersoptions.为acceptAllDevicesfalse,则返回以TypeError拒绝的 promise。Note: 这强制要求filters与必须且仅能有一个存在。acceptAllDevices:true -
令 promise 为一个新的 promise。
-
并行执行以下步骤:
-
请求蓝牙设备,当
options.为acceptAllDevicesfalse时传入options.;否则传入filtersnull。若存在则传入options.,否则传入exclusionFiltersnull;同时传入options.与optionalServicesoptions.,令结果为 devices。optionalManufacturerData -
在Bluetooth 任务源上,针对this的相关全局对象排队一个全局任务以运行以下步骤:
-
若上一步抛出异常,拒绝 promise 并终止这些步骤。
-
如果 devices 是空序列,拒绝 promise,错误为
NotFoundError, 并终止这些步骤。 -
解析 promise,值为
devices[0]。
-
-
-
返回 promise。
BluetoothPermissionStorage
storage、一组可以为 null(表示所有设备可匹配)的
BluetoothLEScanFilterInit
序列 filters、一组可以为 null(表示未设置排除筛选器)的
BluetoothLEScanFilterInit
序列 exclusionFilters、一组
BluetoothServiceUUID
序列 optionalServices,以及一组
unsigned short
序列 optionalManufacturerData,UA 必须执行以下步骤:
-
令 global 为 storage 的相关全局对象。
-
令 document 为 global 的关联 Document。
-
如果 document 未被允许使用名为 "bluetooth" 的策略控制特性,抛出
SecurityError并终止这些步骤。 -
检查该算法是否在其相关全局对象具有瞬时激活期间触发;否则抛出
SecurityError并终止这些步骤。 -
为将参数从服务名称与别名转换为仅UUID,执行以下子步骤:
-
如果
filters !== null && filters.length === 0,抛出TypeError并终止这些步骤。 -
如果
exclusionFilters !== null && exclusionFilters.length === 0,抛出TypeError并终止这些步骤。 -
令 uuidFilters 为新的
Array, uuidExclusionFilters 为新的Array, requiredServiceUUIDs 为新的Set。 -
如果 filters 为
null,则将 requiredServiceUUIDs 设为所有 UUID 的集合。 -
如果 filters 不为
null,则对于 filters 中的每个 filter,执行:-
令 canonicalFilter 为规范化 filter 的结果。
-
将 canonicalFilter 追加到 uuidFilters。
-
将
canonicalFilter.services中的内容添加到 requiredServiceUUIDs。
-
-
如果 exclusionFilters 不为
null,则对于 exclusionFilter 属于 exclusionFilters 的每个元素,执行:-
令 canonicalExclusionFilter 为规范化 exclusionFilter 的结果。
-
将 canonicalExclusionFilter 追加到 uuidExclusionFilters。
-
-
令 optionalServiceUUIDs 为
。Array.prototype.map.call(optionalServices,BluetoothUUID.getService) -
如果任一
BluetoothUUID.getService()调用抛出异常,抛出该异常并终止这些步骤。 -
从 optionalServiceUUIDs 中移除任何在阻止列表中的 UUID。
-
-
令 descriptor 为
{ name: "bluetooth" , filters: uuidFilters optionalServices: optionalServiceUUIDs, optionalManufacturerData: optionalManufacturerData acceptAllDevices: filters!== null , } -
令 state 为 descriptor 的权限状态。
-
如果 state 为 "
denied",返回[]并终止这些步骤。 -
如果 UA 能证明下一步不可能找到任何设备(例如没有用于扫描的蓝牙适配器,或筛选器不可能匹配任何广告包),UA 可以返回
[]并终止这些步骤。 -
令 scanResult 为以 global 与 requiredServiceUUIDs 调用扫描设备的结果。
-
如果 filters 不为
null,则: -
令 navigable 为 document 的navigable。
-
令 promptId 为新的唯一不透明字符串。
实际上,设备列表会在提示框打开期间动态更新。规范文本目前尚未反映这一点,但该事件可能会带着相同的 promptId 和新的设备列表多次触发。参见
https://github.com/WebBluetoothCG/web-bluetooth/issues/621。
-
触发“提示已更新”事件,传入 navigable、promptId 和 scanResult。
-
即使 scanResult 为空,也要提示用户进行选择, 从 scanResult 中选择一个设备,与 descriptor 关联,令结果为 device。
UA 可以允许用户选择一个不匹配 uuidFilters 的附近设备。
Note: UA 应显示每台设备的人类可读名称。如果该名称不可用(例如 UA 的蓝牙系统不支持开启隐私的扫描),UA 应允许用户表示兴趣,然后执行不启用隐私的扫描以获取该名称。 -
移除可导航对象到设备提示的映射[navigable 的navigable id]。
-
UA 可以将 device 添加到 storage。
Note: 选择某个 device 可能表示用户意图让该设备出现在"bluetooth" 的额外权限数据的allowedDevices列表中(至少对当前设置对象),其mayUseGATT字段为true;requiredServiceUUIDs 与 optionalServiceUUIDs 的并集中所有服务出现在其allowedServices列表中(以及任何已存在的服务);并且 optionalManufacturerData 中的厂商代码出现在其allowedManufacturerData列表中。 -
如果 device 为 "
denied",返回[]并终止这些步骤。 -
UA 可以选择 填充 Bluetooth 缓存,将 device 内的所有服务添加其中。本步骤中的任何错误均应被忽略。
-
获取表示
BluetoothDevice的对象 device 在 this 内,如有异常则向上传递,并令 deviceObj 为结果。 -
返回
[deviceObj]。
BluetoothLEScanFilterInit
filter 的结果,是按以下步骤返回的 BluetoothLEScanFilterInit:
-
如果 filter 的所有成员均不存在,抛出
TypeError并终止这些步骤。 -
令 canonicalizedFilter 为
{}。 -
如果
filter.存在,执行以下子步骤:services-
如果
filter.services.length === 0,抛出TypeError并终止这些步骤。 -
令 services 为
。Array.prototype.map.call(filter.services,BluetoothUUID.getService) -
若任一
BluetoothUUID.getService()调用抛出异常,抛出该异常并终止这些步骤。 -
如果 services 中的任一服务在阻止列表中,抛出
SecurityError并终止这些步骤。 -
将
canonicalizedFilter.services设为 services。
-
-
如果
filter.存在,执行以下子步骤。name -
如果
filter.存在,执行以下子步骤。namePrefix -
将
canonicalizedFilter["manufacturerData"]设为[]。 -
如果
filter["存在且manufacturerData"]filter["manufacturerData"].length === 0,抛出TypeError并终止这些步骤。 -
对于
filter["中的每个 manufacturerData,执行以下子步骤:manufacturerData"]-
如果 manufacturerData 是被阻止的厂商数据筛选器,抛出
SecurityError并终止这些步骤。 -
如果在
canonicalizedFilter["manufacturerData"]中存在对象 existing,且existing["companyIdentifier"] === manufacturerData[",抛出companyIdentifier"]TypeError并终止这些步骤。 -
令 canonicalizedManufacturerDataFilter 为规范化 manufacturerData 的结果,并转换为 ECMAScript 值。若抛出异常,传播该异常并终止这些步骤。
-
将
canonicalizedManufacturerDataFilter["companyIdentifier"]设为manufacturerData["。companyIdentifier"] -
将 canonicalizedManufacturerDataFilter 追加到
canonicalizedFilter["manufacturerData"]。
-
-
将
canonicalizedFilter.serviceData设为[]。 -
如果
filter["存在且serviceData"]filter["serviceData"].length === 0,抛出TypeError并终止这些步骤。 -
对于
filter["中的每个 serviceData,执行以下子步骤:serviceData"]-
令 service 为
。 若抛出异常,传播该异常并终止这些步骤。BluetoothUUID.getService(serviceData["service"]) -
如果 service在阻止列表中,抛出
SecurityError并终止这些步骤。 -
令 canonicalizedServiceDataFilter 为规范化 serviceData 的结果,并转换为 ECMAScript 值。若抛出异常,传播该异常并终止这些步骤。
-
将
canonicalizedServiceDataFilter["service"]设为 service。 -
将 canonicalizedServiceDataFilter 追加到
canonicalizedFilter["serviceData"]。
-
-
返回 canonicalizedFilter。
BluetoothDataFilterInit
filter 的结果,是按以下步骤返回的 BluetoothDataFilterInit:
-
如果
filter.不存在,则令 dataPrefix 为空字节序列。否则,执行以下子步骤:dataPrefix -
如果
filter.存在,则令 mask 为 由字节构成的拷贝,其来源为maskfilter.mask。否则,令 mask 为与 dataPrefix 相同长度的0xFF字节序列。 -
如果 mask 的长度与 dataPrefix 不同,抛出
TypeError并终止这些步骤。 -
返回
{dataPrefix: new Uint8Array(|dataPrefix|), mask: new Uint8Array(|mask|)}。
-
如果 UA 最近使用一个 UUID 集合扫描过设备,且该集合是当前扫描所用 UUID 集合的超集,则 UA 可以返回那次扫描的结果并中止这些步骤。
-
令 simulatedBluetoothDevices 为一个空列表。
-
如果 topLevelTraversable 具有模拟蓝牙适配器,则令 simulatedBluetoothDevices 为其获取映射值后的 模拟蓝牙设备映射的结果。
-
如果 UA 支持 LE 传输,执行常规发现流程(General Discovery Procedure),但 UA 可以包含未设置可发现模式(Discoverable Mode)标志的设备,并将发现的蓝牙设备加入 nearbyDevices。UA 应启用隐私功能(Privacy Feature)。
被动扫描(passive scanning)与隐私功能都可避免泄露唯一且不可变的设备 ID。我们本应要求 UA 使用其中之一,但没有任何操作系统 API 似乎暴露了这两者。并且由于蓝牙不要求中心设备(Central)支持观察流程(Observation Procedure),因此也很难使用被动扫描。
-
如果 UA 支持 BR/EDR 传输,执行设备发现流程(Device Discovery Procedure)并将发现的蓝牙设备加入 nearbyDevices。
-
令 result 为一组蓝牙设备,初始为空。
-
对 nearbyDevices 与 simulatedBluetoothDevices 中的每个蓝牙设备 device,执行以下子步骤:
-
如果 device 的支持的物理传输包含 LE,且其蓝牙设备名是不完整的或缺失,UA 应执行名称发现流程(Name Discovery Procedure)以获取完整名称。
-
如果 device 广播的服务 UUID与服务 UUID 集合有非空交集,则将 device 加入 result 并中止这些子步骤。
注意:对于 BR/EDR 设备,无法在扩展查询响应(Extended Inquiry Response)中区分 GATT 与非 GATT 服务。如果站点按某个非 GATT 服务的 UUID 进行过滤,用户可能会在requestDevice的结果中选择一个本 API 无法与之交互的设备。 -
UA 可以连接到 device 并填充蓝牙缓存,包含所有 UUID 位于服务 UUID 集合中的服务。如果 device 的支持的物理传输包含 BR/EDR,则除了标准 GATT 流程外,UA 也可以在填充缓存时使用服务发现协议(Searching for Services)。
-
如果蓝牙缓存中包含 device 内已知存在、且其 UUID 位于服务 UUID 集合中的服务,UA 可以将 device 加入 result。
-
-
从扫描中返回 result。
BluetoothPermissionStorage
storage,在给定一组 requiredServiceUUIDs 与一组 optionalServiceUUIDs 的情况下,UA
必须执行以下步骤:
-
令 grantedServiceUUIDs 为新的
Set。 -
将 requiredServiceUUIDs 的内容添加到 grantedServiceUUIDs。
-
将 optionalServiceUUIDs 的内容添加到 grantedServiceUUIDs。
-
在
storage.中查找元素 allowedDevice,其满足 device 等于allowedDevicesallowedDevice@。 如果找到,执行以下子步骤:[[device]]-
将
allowedDevice.的内容添加到 grantedServiceUUIDs。allowedServices
如果未找到,执行以下子步骤:
-
令 allowedDevice.
deviceId为一个唯一 ID,其唯一性取决于 UA 能在何种程度上判定两次蓝牙连接来自同一设备,以及 用户希望在何种程度上将这一事实暴露给脚本。
-
-
将 allowedDevice.
allowedServices设为 grantedServiceUUIDs。 -
将 allowedDevice.
mayUseGATT设为true。
要从存储中移除一个已获准的 蓝牙
设备 device,给定 BluetoothPermissionStorage
storage,UA 必须执行以下步骤:
-
在
storage.中查找元素 allowedDevice,其满足 device 等于allowedDevicesallowedDevice@。 若不存在此类元素,中止这些步骤。[[device]] -
从
storage.中移除 allowedDevice。allowedDevices
4.1. 权限 API 集成
[permissions] API 为网站提供了统一的方式来查询其拥有哪些权限。
navigator. permissions. query({ name: "bluetooth" ,
...}) 在重新加载后取回这些设备。
navigator. permissions. query({ name: "bluetooth" , deviceId: sessionStorage. lastDevice, }). then( result=> { if ( result. devices. length== 1 ) { return result. devices[ 0 ]; } else { throw new DOMException( "Lost permission" , "NotFoundError" ); } }). then(...);
Web Bluetooth API 是一个由 强能力(powerful feature)标识的功能,其 name 为 "bluetooth"。其与权限相关的算法与类型定义如下:
- 权限描述符类型
-
dictionary :BluetoothPermissionDescriptor PermissionDescriptor {DOMString ; // 这些与 RequestDeviceOptions 对应。deviceId sequence <BluetoothLEScanFilterInit >;filters sequence <BluetoothServiceUUID >= [];optionalServices sequence <unsigned short >= [];optionalManufacturerData boolean =acceptAllDevices false ; }; - 额外权限数据类型
-
BluetoothPermissionStorage, 定义如下:dictionary {AllowedBluetoothDevice required DOMString ;deviceId required boolean ; // allowedServices 为 "all" 表示允许所有服务。mayUseGATT required (DOMString or sequence <UUID >);allowedServices required sequence <unsigned short >; };allowedManufacturerData dictionary {BluetoothPermissionStorage required sequence <AllowedBluetoothDevice >; };allowedDevices AllowedBluetoothDevice实例具有一个 内部槽位[[device]],其保存一个 蓝牙设备。 - 额外权限数据约束
-
allowedDevices的各元素必须具有不同的[[device]]和不同的deviceId。如果
mayUseGATT为false,allowedServices和allowedManufacturerData都必须为[]。注意:deviceId允许站点跟踪某一时刻看到的BluetoothDevice实例与另一个时刻(可能在不同的 realm)看到的BluetoothDevice实例是否代表同一设备。当返回 "bluetooth" 的 额外权限数据时,UA 应考虑用户是否意图发生这种跟踪。例如,用户通常并不希望两个不同的源知道他们正在与同一设备交互,也通常不希望在清除某个源的 cookie 后,唯一标识符仍然保留。
- 权限结果类型
-
[
Exposed =Window ]interface :BluetoothPermissionResult PermissionStatus {attribute FrozenArray <BluetoothDevice >; };devices - 权限查询算法
-
要用
BluetoothPermissionDescriptordesc 和BluetoothPermissionResultstatus 来查询 "bluetooth" 权限,UA 必须:-
令 global 为 status 的相关全局对象。
-
如果
status.为 "statedenied", 则将status.devices设为一个空的FrozenArray并终止这些步骤。 -
令 matchingDevices 为一个新的
Array。 -
令 storage(一个
BluetoothPermissionStorage)为 "bluetooth" 针对当前设置对象的 额外权限数据。 -
对于
storage.allowedDevices中的每个 allowedDevice,执行以下子步骤:-
如果
desc.deviceId已设置且allowedDevice.deviceId != desc.deviceId,继续下一个 allowedDevice。 -
如果
desc.filters已设置,执行以下子步骤:-
将
desc.filters中的每个筛选器替换为对其进行规范化的结果。若任何规范化抛出错误,返回该错误并终止这些步骤。 -
如果
allowedDevice.不 匹配任一筛选器 于[[device]]desc.filters,则继续下一个 allowedDevice。
-
-
获取表示
allowedDevice.的[[device]]BluetoothDevice,位于global.navigator.bluetooth内,并将结果添加到 matchingDevices。
注意:desc.optionalServices与desc.optionalManufacturerData字段不影响结果。 -
-
将
status.devices设为一个新的FrozenArray, 其内容为 matchingDevices。
-
- 权限撤销算法
-
要对用户不再意图暴露的设备撤销蓝牙访问,UA 必须执行以下步骤:
-
令 storage(一个
BluetoothPermissionStorage)为 "bluetooth" 针对当前设置对象的 额外权限数据。 -
对于当前realm 中的每个
BluetoothDevice实例 deviceObj,执行以下子步骤:-
若在
storage.中存在allowedDevicesAllowedBluetoothDeviceallowedDevice,满足:-
allowedDevice.与[[device]]deviceObj.是同一设备,且[[representedDevice]]
则将
deviceObj.更新为[[allowedServices]]allowedDevice., 并继续下一个 deviceObj。allowedServices -
-
否则,通过运行以下剩余步骤,将 deviceObj 与其设备分离。
-
调用
deviceObj.gatt.。disconnect()注意:这会在 deviceObj 上触发gattserverdisconnected事件。 -
将
deviceObj.设为[[representedDevice]]null。
-
-
4.2. 整体蓝牙可用性
UA 可能运行在没有蓝牙射频的计算机上。
requestDevice()
在这种情况下将无法发现任何设备,从而导致 NotFoundError,
不过网站可以更优雅地处理这种情况。
const bluetoothUI= document. querySelector( '#bluetoothUI' ); navigator. bluetooth. getAvailability() . then( isAvailable=> { bluetoothUI. hidden= ! isAvailable; }); navigator. bluetooth. addEventListener( ' availabilitychanged ' , e=> { bluetoothUI. hidden= ! e. value; });
getAvailability()
方法时,必须返回一个新的 promise promise,并并行运行以下步骤:
-
如果 global 的关联的 Document未被允许使用名为 "bluetooth" 的策略控制特性,则针对给定的 global 在Bluetooth 任务源上排队一个全局任务以解析 promise 为
false,并终止这些步骤。 -
如果用户已将 UA 配置为对当前来源从该函数返回特定答案,则排队一个任务以解析 promise 为该配置的答案,并终止这些步骤。
注意:如果 Web Bluetooth 权限已被用户阻止,UA 可以将 promise 解析为false。 -
令 simulatedBluetoothAdapter 为 this 的navigable 的 顶层可遍历对象的 模拟蓝牙适配器。
-
如果 simulatedBluetoothAdapter 非空,
-
如果 simulatedBluetoothAdapter 的适配器状态为 "absent",则针对给定的 global 在Bluetooth 任务源上排队一个全局任务以解析 promise 为
false。 -
如果 simulatedBluetoothAdapter 的LE 支持状态为
false,则针对给定的 global 在Bluetooth 任务源上排队一个全局任务以解析 promise 为false。 -
否则,针对给定的 global 在Bluetooth 任务源上排队一个全局任务以解析 promise 为
true。 -
终止这些步骤。
-
-
如果 UA 运行在具有蓝牙射频的系统上,则针对给定的 global 在Bluetooth 任务源上排队一个全局任务以解析 promise 为
true,无论蓝牙射频的供电状态如何。 -
否则,针对给定的 global 在Bluetooth 任务源上排队一个全局任务以解析 promise 为
false。注意:该 promise 被并行解析,以便 UA 调用其他系统来确定蓝牙是否可用。
getAvailability
的 promise 解析为 false,则可以使用以下方法检测蓝牙何时再次可用以显示蓝牙 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(); // 蓝牙被阻止,监听 PermissionStatus 的变化。 status. onchange= () => { if ( this . state!== 'denied' ) checkAvailability(); }; });
-
令 oldAvailability 为变更前
getAvailability()将会返回的值。 -
令 newAvailability 为变更后
getAvailability()将会返回的值。 -
如果 oldAvailability 与 newAvailability 不同,
-
令 navigator 为 global 的关联
Navigator。 -
令 bluetooth 为 navigator 的关联
Bluetooth。 -
触发一个事件,名称为
availabilitychanged, 使用ValueEvent接口,在 bluetooth 上触发,并将其value属性初始化为 newAvailability。
-
[Exposed =Window ,SecureContext ]interface :ValueEvent Event {(constructor DOMString ,type optional ValueEventInit = {});initDict readonly attribute any value ; };dictionary :ValueEventInit EventInit {any =value null ; };
ValueEvent
实例的构造遵循
DOM § 2.5 事件的构造。
value 属性必须返回其被初始化时的值。
此类通用事件类型应属于 [HTML] 或 [DOM],而非本规范。
5. 设备表示
UA 需要在多个层级跟踪蓝牙设备属性:全局、按源(origin),以及按全局对象。
5.1. 全局蓝牙设备属性
物理蓝牙设备可能保证具有某些 UA 尚未接收的属性。此处将这些属性描述为可选。
蓝牙设备具有以下属性。可选 属性在未另行说明之前不存在,序列与映射属性为空。其他属性具有指定的默认值,或在设备被引入时指定。
-
一组支持的物理传输,包括 BR/EDR 和/或 LE。该集合通常基于发现设备所用的传输以及 Flags 数据类型(位于 广告数据或 扩展查询响应中)来填充。
-
可选的 128 位身份解析密钥。
-
可选的部分或完整蓝牙设备名。当接收到 缩短的本地名称(Shortened Local Name) AD 数据但尚未读取完整名称时,设备处于部分名称状态。蓝牙设备名 以 UTF-8 编码,并使用无 BOM 的 utf-8 解码算法转换为 DOMString。
-
可选的ATT 承载体,所有 GATT 通信均通过其进行。ATT 承载体通过 GAP 互操作性要求下“连接建立”中描述的流程创建。其断开方式在 [BLUETOOTH42] 中并不完全清晰。
-
GATT 属性的层级结构。
UA 应当仅当且仅当两个蓝牙设备具有相同的公共蓝牙地址、静态地址、私有地址或身份解析密钥,或使用一方的 IRK 与另一方的可解析私有地址成功执行可解析私有地址解析过程时,认定它们是同一蓝牙设备。然而,由于平台 API 并未文档化其判定设备身份的方法,UA 可以采用其他过程。
5.2. BluetoothDevice
BluetoothDevice
实例表示某个特定蓝牙设备,对应某个特定的全局对象(或等价地,某个特定的Realm或 Bluetooth
实例)。
[Exposed =Window ,SecureContext ]interface :BluetoothDevice EventTarget {readonly attribute DOMString id ;readonly attribute DOMString ?name ;readonly attribute BluetoothRemoteGATTServer ?gatt ;Promise <undefined >forget ();Promise <undefined >watchAdvertisements (optional WatchAdvertisementsOptions = {});options readonly attribute boolean watchingAdvertisements ; };BluetoothDevice includes BluetoothDeviceEventHandlers ;BluetoothDevice includes CharacteristicEventHandlers ;BluetoothDevice includes ServiceEventHandlers ;dictionary {WatchAdvertisementsOptions AbortSignal ; };signal
BluetoothDevice
属性id 在 UA 能够判定两次蓝牙连接指向同一设备且用户
希望将这一事实暴露给脚本的范围内,对设备进行唯一标识。
name 是设备的人类可读名称。
gatt
在站点有权限的前提下,提供与该设备的 GATT 服务器交互的方式。
forget()
使页面能够撤销用户已授予的该设备访问权限。
watchingAdvertisements 为 true 表示
UA 当前正在扫描来自该设备的广告并为其触发事件。
BluetoothDevice
实例在创建时携带如下内部槽位(见下表):
| 内部槽位 | 初始值 | 描述(非规范性) |
|---|---|---|
[[context]]
| <总在正文中设定> |
返回此 Bluetooth
对象的 BluetoothDevice。
|
[[representedDevice]]
| <总在正文中设定> |
此对象所表示的蓝牙设备;
若访问已被撤销,则为 null。
|
[[gatt]]
|
一个新的 BluetoothRemoteGATTServer
实例,其
device
属性被初始化为 this,其
connected
属性被初始化为 false。
| 不会改变。 |
[[allowedServices]]
| <总在正文中设定> |
此设备在该源下的 allowedServices
列表;若允许所有服务,则为 "all"。例如,UA 可以为某源授予其在该源上通过
referringDevice
广告的 URL 上的所有服务访问权限。
|
[[allowedManufacturerData]]
| <总在正文中设定> |
此设备在该源下的 allowedManufacturerData
列表。
|
[[watchAdvertisementsState]]
| 'not-watching'
|
一个字符串枚举,描述一次
watchAdvertisements()
操作的当前状态。可能的枚举值包括:
|
BluetoothDevice 的对象:给定某个蓝牙设备
device,以及 Bluetooth
实例
context,UA 必须执行以下步骤:
-
令 storage(一个
BluetoothPermissionStorage)为 "bluetooth" 针对额外权限数据的 当前设置对象。 -
在
storage.中查找其allowedDevicesallowedDevice.与 device为同一设备的 allowedDevice。若没有此对象,则抛出[[device]]SecurityError并中止这些步骤。 -
若在 context.
[[deviceInstanceMap]]中不存在与 device为同一设备的键,则执行以下子步骤:-
令 result 为
BluetoothDevice的新实例。 -
将 result 的所有可选字段初始化为
null。 -
将
result.初始化为 context。[[context]] -
将
result.初始化为 device。[[representedDevice]] -
将
result.id初始化为allowedDevice., 并将deviceIdresult.初始化为[[allowedServices]]allowedDevice.。allowedServices -
若 device 具有部分或完整蓝牙设备名,则将
result.name设为该字符串。 -
将
result.watchingAdvertisements初始化为false。 -
在 context.
[[deviceInstanceMap]]中添加从 device 到 result 的映射。
-
-
返回 context.
[[deviceInstanceMap]]中以与 device为同一设备为键的值。
gatt
属性必须执行以下步骤:
-
如果针对
this的"bluetooth"的额外权限数据(对应其相关设置对象)的AllowedBluetoothDevice列表allowedDevices中存在 allowedDevice,满足allowedDevice.与[[device]]this.为同一设备,且[[representedDevice]]allowedDevice.等于mayUseGATTtrue,则返回this.。[[gatt]] -
否则,返回
null。
forget()
方法时,必须返回一个新的 promise promise,并执行以下步骤:
-
令 device 为目标
BluetoothDevice对象。 -
令 storage 为当前脚本执行环境中的
BluetoothPermissionStorage对象。 -
使用 storage从存储中移除 device。
-
解析 promise。
用户代理具有关联的广告监视管理器,其为启动一个新的并行队列的结果。
watchAdvertisements(options)
方法时,必须返回一个新的 promise
promise,并执行以下步骤:
-
如果
options.存在,则执行以下子步骤:signal-
如果
options.已中止,则以signalthis为对象中止 watchAdvertisements 并中止这些步骤。 -
-
以
this为对象中止 watchAdvertisements。 -
拒绝 promise,错误为
AbortError。
-
-
-
若
this.为:[[watchAdvertisementsState]]'not-watching'-
-
将
this.设为[[watchAdvertisementsState]]'pending-watch'。 -
将以下步骤入队至广告监视管理器,但当
this.变为[[watchAdvertisementsState]]not-watching时中止:-
确保 UA 正在扫描该设备的广告。UA 不应筛除同一设备的“重复”广告。
-
若 UA 启用扫描失败,则在给定 global 的 Bluetooth 任务源上排队一个全局任务以执行以下步骤,并中止这些步骤:
-
将
this.设为[[watchAdvertisementsState]]'not-watching'。 -
拒绝 promise,错误为下列之一:
- UA 不支持扫描广告
- 蓝牙已关闭
- 其他原因
-
-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以执行以下步骤,但当 满足中止条件(即
this.变为[[watchAdvertisementsState]]not-watching)时中止:-
将
this.设为[[watchAdvertisementsState]]watching。 -
将
this.设为watchingAdvertisementstrue。 -
解析 promise,值为
undefined。
-
-
-
'pending-watch'-
-
拒绝 promise,错误为
InvalidStateError。
-
'watching'-
-
解析 promise,值为
undefined。
-
-
若已中止,拒绝 promise,错误为
AbortError。
Note: 扫描会消耗电量,因此网站应避免不必要地监视广告,并应使用其
AbortController
尽快停止耗电。
watchAdvertisements
的
BluetoothDevice
device,执行以下步骤:
-
将
this.设为[[watchAdvertisementsState]]'not-watching'。 -
将
device.设为watchingAdvertisementsfalse。 -
-
如果整个 UA 中不再有任何
BluetoothDevice的watchingAdvertisements为true,UA 应停止扫描广告。否则,若不再有任何与this表示同一设备的BluetoothDevice的watchingAdvertisements为true,UA 应重新配置扫描以避免接收该设备的报告。
-
Bluetooth
bluetooth 的情况下中止所有活动的 watchAdvertisements
操作,执行以下步骤:
-
对每个位于 bluetooth.
[[deviceInstanceMap]]中的 device 执行以下步骤:-
如果 device.
[[watchAdvertisementsState]]为pending-watch或watching,则以 device为对象运行中止 watchAdvertisements。
-
5.2.1. 处理可见性变化
启动蓝牙设备扫描的操作只能在可见的document 中运行。当visibility state不再为
"visible"时,需要中止该document的扫描操作。
-
令 global 为 document 的相关全局对象。
-
在给定 global 的Bluetooth 任务源上排队一个全局任务以执行以下步骤:
-
令 navigator 为 global 的关联
Navigator。 -
令 bluetooth 为 navigator 的关联
Bluetooth。 -
如果 visibilityState 不为
"visible",则在 bluetooth 上中止所有活动的 watchAdvertisements 操作。
-
5.2.2. 处理文档失去完全活动状态
启动蓝牙设备扫描的操作只能在完全活动的document中运行。当完全活动状态丢失时,需要中止该document的扫描操作。
Document
不再完全活动时,必须运行以下步骤:
-
令 global 为 document 的相关全局对象。
-
在给定 global 的Bluetooth 任务源上排队一个全局任务以执行以下步骤:
-
令 navigator 为 global 的关联
Navigator。 -
令 bluetooth 为 navigator 的关联
Bluetooth。 -
在 bluetooth 上运行中止所有活动的 watchAdvertisements 操作。
-
5.2.3. 响应广播事件
当某个BluetoothDevice设置了
watchingAdvertisements
时收到advertising
event,UA 将投递一个 "advertisementreceived"
事件。
[Exposed =Window ,SecureContext ]interface BluetoothManufacturerDataMap {readonly maplike <unsigned short ,DataView >; }; [Exposed =Window ,SecureContext ]interface BluetoothServiceDataMap {readonly maplike <UUID ,DataView >; }; [Exposed =Window ,SecureContext ]interface :BluetoothAdvertisingEvent Event {constructor (DOMString ,type BluetoothAdvertisingEventInit ); [init SameObject ]readonly attribute BluetoothDevice device ;readonly attribute FrozenArray <UUID >uuids ;readonly attribute DOMString ?name ;readonly attribute unsigned short ?appearance ;readonly attribute byte ?txPower ;readonly attribute byte ?rssi ; [SameObject ]readonly attribute BluetoothManufacturerDataMap manufacturerData ; [SameObject ]readonly attribute BluetoothServiceDataMap serviceData ; };dictionary :BluetoothAdvertisingEventInit EventInit {required BluetoothDevice ;device sequence <(DOMString or unsigned long )>;uuids DOMString ;name unsigned short ;appearance byte ;txPower byte ;rssi BluetoothManufacturerDataMap ;manufacturerData BluetoothServiceDataMap ; };serviceData
BluetoothAdvertisingEvent
属性device 是发送此广播的 BluetoothDevice。
uuids 列出该广播声称
device
的 GATT 服务器所支持的服务 UUID。
name 是 device
的本地名称,或其前缀。
appearance 是一个Appearance,取值为
gap.appearance
特征定义的值之一。
txPower
为设备进行广播时的发射功率(单位 dBm)。用于按
this.txPower - this.rssi 计算路径损耗。
rssi 为接收到该广播时的功率(单位
dBm)。用于按
this.txPower -
this.rssi 计算路径损耗。
manufacturerData 将
unsigned short 公司标识符映射到 DataView。
requestDevice 对话框中选择此设备。
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}); });
iBeacon 广播的格式参考自 Adam Warski 的How do iBeacons work?。
-
令 device 为发送该广播事件的蓝牙设备。
-
对于 UA 中的每个
BluetoothDevicedeviceObj,使得 device 与deviceObj.为同一设备,在 deviceObj 的相关设置对象的负责的事件循环上排队一个任务以执行以下子步骤:[[representedDevice]]-
如果
deviceObj.为watchingAdvertisementsfalse,则中止这些子步骤。 -
在 deviceObj 上触发一个
advertisementreceived事件,用于该广播事件。
-
BluetoothDevice
deviceObj 上,为一个广播事件 adv触发一个 advertisementreceived
事件,UA 必须执行以下步骤:
-
令 event 为
{ bubbles: true , device: deviceObj, uuids: [], manufacturerData: new Map(), serviceData: new Map() } -
如果 adv 中任一数据包可用接收信号强度,则将
event.rssi设为该以 dBm 计的信号强度。 -
对于 adv 的广播数据包和扫描响应中的每个AD 结构,根据 AD 类型按以下步骤进行:
-
16 位服务 UUID不完整列表
- 16 位服务 UUID完整列表
- 32 位服务 UUID不完整列表
- 32 位服务 UUID完整列表
- 128 位服务 UUID不完整列表
- 128 位服务 UUID完整列表
- 16 位服务 UUID完整列表
-
对列出的每个
uuid,如果其包含在this.device.中,则将[[allowedServices]]uuid追加到event.uuids。 - 缩短的本地名称
- 完整本地名称
-
对 AD 数据进行无 BOM 的 UTF-8 解码,并将
event.name设为结果。注意:我们不暴露名称是否完整,因为现有 API 需要读取原始广播才能获知该信息;在将该字段加入 API 前,我们希望获得更多其有用性的证据。 - 厂商特定数据
-
对每个 16 位公司标识符
manufacturerCode,如果其包含在this.device.中,且该厂商数据不是阻止列表中的厂商数据,则将[[allowedManufacturerData]]manufacturerCode映射到一个包含该厂商特定数据的ArrayBuffer并加入到event.manufacturerData。 - TX 发射功率等级
-
将
event.txPower设为 AD 数据。 - 服务数据
- 16 位 UUID
- 服务数据 - 32 位 UUID
- 服务数据 - 128 位 UUID
- 服务数据 - 32 位 UUID
-
对服务数据中的每个UUID
uuid,如果其包含在this.device.中,则将 uuid 映射到一个包含该服务数据的[[allowedServices]]ArrayBuffer并加入到event.serviceData。 - 外观(Appearance)
-
将
event.appearance设为 AD 数据。 - 否则
- 跳过到下一个 AD 结构。
-
16 位服务 UUID不完整列表
-
在 deviceObj 上,使用以 event 初始化、其
isTrusted属性初始化为true的BluetoothAdvertisingEvent,触发一个事件,名称为 "advertisementreceived"。
BluetoothAdvertisingEvent
中的所有字段都会返回它们上次被初始化或设置的值。
BluetoothAdvertisingEvent(type, init)
构造函数必须执行以下步骤:
-
令 event 为运行 DOM § 2.5 事件的构造步骤(但不包括
uuids、manufacturerData和serviceData成员)所得的结果。 -
如果
init.uuids已设置,则将event.uuids初始化为一个新的FrozenArray,其元素为init.uuids.map(的结果。否则,将BluetoothUUID.getService)event.uuids初始化为一个空的FrozenArray。 -
对于
init.manufacturerData中的每个映射:-
令 code 为将键转换为
unsigned short的结果。 -
令 value 为该值。
-
如果 value 不是
BufferSource,抛出TypeError。 -
令 bytes 为一个新的只读 ArrayBuffer,其中包含由value持有字节的拷贝。
-
在
event.manufacturerData.中添加从 code 到[[BackingMap]]new DataView(bytes)的映射。
-
-
对于
init.serviceData中的每个映射:-
令 key 为该键。
-
令 service 为调用
BluetoothUUID.的结果。getService(key). -
令 value 为该值。
-
如果 value 不是
BufferSource,抛出TypeError。 -
令 bytes 为一个新的只读 ArrayBuffer,其中包含由value持有字节的拷贝。
-
在
event.serviceData.中添加从 service 到[[BackingMap]]new DataView(bytes)的映射。
-
-
返回 event。
5.2.3.1. BluetoothManufacturerDataMap
BluetoothManufacturerDataMap
实例具有一个 [[BackingMap]]
槽位,因为它们是maplike,该槽位将厂商代码映射到厂商数据,并转换为 DataView。
5.2.3.2. BluetoothServiceDataMap
BluetoothServiceDataMap
实例具有一个 [[BackingMap]] 槽位,因为它们是maplike,该槽位将服务 UUID 映射到服务数据,并转换为 DataView。
6. GATT 交互
6.1. GATT 信息模型
配置文件(Profile)是纯逻辑的:Profile 的规范描述了该 Profile 所包含的其它 GATT 实体之间期望的交互,但无法查询设备支持哪些 Profile。
GATT 客户端可以通过一组GATT 流程来发现并与设备上的服务(Services)、特征值(Characteristics)和描述符(Descriptors)交互。本文将服务、特征值与描述符统称为属性(Attribute)。所有属性都有由UUID标识的类型。每个属性还有一个 16 位的属性句柄(Attribute Handle),用于将其与同一GATT 服务器上相同类型的其他属性区分开来。属性在其GATT 服务器内名义上按其属性句柄排序,但尽管平台接口会以某种顺序提供属性,它们并不保证该顺序与属性句柄顺序一致。
一个服务(Service)包含一组包含的服务(Included Service)和特征值(Characteristic)。包含的服务是对其他服务的引用,单个服务可以被多个其他服务包含。服务若直接位于GATT 服务器之下,则称为主服务(Primary Services);如果仅被其他服务包含,则为次级服务(Secondary Services),但主服务也可以被包含。
一个特征值(Characteristic)包含一个字节数组形式的值,以及一组描述符(Descriptor)。根据该特征值的属性(properties),GATT 客户端可以读取或写入其值,或注册在其值发生变化时得到通知。
最后,描述符(Descriptor)包含一个(同样是字节数组的)值,用于描述或配置其所属的特征值(Characteristic)。
6.1.1. 跨连接的持久性
蓝牙的属性缓存(Attribute
Caching)系统允许已绑定(bonded)的客户端在一次连接到下一次连接之间保存对属性的引用。Web Bluetooth 将网站视为与其有权限访问的设备未绑定:BluetoothRemoteGATTService、
BluetoothRemoteGATTCharacteristic,
以及BluetoothRemoteGATTDescriptor
对象在断开连接时变为无效,站点在再次连接时必须重新获取它们。
6.1.2. 蓝牙缓存
UA 必须维护一个关于其在某设备上发现的服务、特征值与描述符层级结构的蓝牙缓存。UA
可以在多个访问同一设备的源(origin)之间共享该缓存。缓存中的每个潜在条目要么是“已知存在(known-present)”,要么是“已知不存在(known-absent)”,要么是“未知(unknown)”。缓存不得包含两个针对同一属性的条目。缓存中每个已知存在的条目,在每个
Bluetooth
实例下,都关联一个可选的
Promise<、
BluetoothRemoteGATTService>Promise<,
或
BluetoothRemoteGATTCharacteristic>Promise<
实例。
BluetoothRemoteGATTDescriptor>
serviceA.getCharacteristic(uuid1),UA 会使用按 UUID
发现特征值(Discover Characteristics by UUID)流程来填充所需的缓存条目,并且因为只需要一个特征值来履行返回的Promise,UA
可能会提前结束该流程,那么
serviceA 内第一个 UUID 为 uuid1 的特征值就变为已知存在,而该 UUID 的后续特征值仍保持未知。如果用户稍后调用
serviceA.getCharacteristics(uuid1),UA 需要恢复或重启按 UUID
发现特征值流程。如果最终发现 serviceA 只有一个 UUID 为
uuid1 的特征值,那么后续的特征值将变为已知不存在。
蓝牙缓存中的已知存在条目是有序的:主服务在设备内部具有特定顺序;包含的服务与特征值在其服务内部具有特定顺序;描述符在其特征值内部具有特定顺序。该顺序应当与设备上的属性句柄顺序匹配,但如果设备的顺序不可用,UA 可以使用其他顺序。
-
尝试使用任何GATT 流程的序列,只要[BLUETOOTH42]规定它们将返回足够的信息,即可将缓存中所有匹配的条目标记为已知存在或已知不存在。按§ 6.7 错误处理所述处理错误。
-
如果上一步返回错误,则从本算法返回该错误。
BluetoothDevice
实例 deviceObj 中查询蓝牙缓存以获取与某种描述相匹配的条目,UA 必须返回一个包裹在
deviceObj.gatt-连接检查包装器内的新
promisepromise,并并行运行以下步骤:
-
令 global 为 deviceObj 的相关全局对象。
-
填充蓝牙缓存,使其包含匹配该描述的条目。
-
如果上一步返回错误,则在给定 global 的Bluetooth 任务源上排队一个全局任务以拒绝promise并附带该错误,然后中止这些步骤。
-
令 entries 为与该描述匹配的“已知存在”的缓存条目序列。
-
令 context 为 deviceObj.
[[context]]。 -
令 result 为一个新的序列。
-
对于 entries 中的每个 entry:
-
如果 entry 在 context.
[[attributeInstanceMap]]中没有关联的Promise<BluetoothGATT*>实例,则视 entry 的类型(服务、特征值或描述符),分别创建一个表示该条目的BluetoothRemoteGATTService、创建一个表示该条目的BluetoothRemoteGATTCharacteristic,或者创建一个表示该条目的BluetoothRemoteGATTDescriptor,并在 context.[[attributeInstanceMap]]中添加从 entry 到所得到的Promise的映射。 -
将与 entry 关联的
Promise<BluetoothGATT*>实例追加到 context.[[attributeInstanceMap]]中对应的 result。
-
-
在给定 global 的Bluetooth 任务源上排队一个全局任务,以解析promise,其值为等待所有result元素完成后的结果。
6.1.3. 导航蓝牙层级
single: boolean,
uuidCanonicalizer: function,
uuid: optional
(DOMString or unsigned int),allowedUuids: optional
("all" or Array<DOMString>),child type: GATT declaration type),
UA 必须执行以下步骤:
-
如果存在 uuid,则将其设为 uuidCanonicalizer(uuid)。如果 uuidCanonicalizer 抛出了异常,返回一个以该异常拒绝的 promise,并中止这些步骤。
-
如果存在 uuid 且其在阻止列表中,返回一个被拒绝的 promise,错误为
SecurityError,并中止这些步骤。 -
令 deviceObj 为(取决于 attribute 的类型):
BluetoothDeviceattributeBluetoothRemoteGATTServiceattribute.deviceBluetoothRemoteGATTCharacteristicattribute.service.device
-
如果
deviceObj.gatt.为connectedfalse,返回一个被拒绝的 promise,错误为NetworkError,并中止这些步骤。 -
如果 Represented(attribute) 为
null,返回一个被拒绝的 promise,错误为InvalidStateError,并中止这些步骤。Note: 当某个服务或特征值从设备上被移除或因断开连接而失效后又被再次使用时,就会出现这种情况。
-
在
deviceObj中查询蓝牙缓存,查找满足以下条件的条目:-
位于 Represented(attribute) 之内,
-
其类型由 child type 描述,
-
其 UUID 不在阻止列表中,
-
如果存在 uuid,则其 UUID 等于 uuid,
-
如果存在 allowedUuids 且不为
"all",则其 UUID 在 allowedUuids 中,且 -
如果设置了 single 标志,则只取这些中的第一个。
令 promise 为该结果。
-
-
当promise完成并给出 result 时,运行以下步骤:
-
如果 result 为空,抛出
NotFoundError。 -
否则,如果设置了 single 标志,返回 result 的第一个(也是唯一一个)元素。
-
否则,返回 result。
-
6.1.4. 标识服务、特征值和描述符
在检查两个服务、特征值或描述符 a 与 b 是否为同一属性时,UA 应当在 a 与 b 位于同一设备且具有相同属性句柄时认定它们相同,但 UA 可以使用任何算法,只要满足以下约束:若符合下列任一条件,a 与 b不得被认为是同一属性:
6.2. BluetoothRemoteGATTServer
BluetoothRemoteGATTServer
表示远程设备上的GATT 服务器。
[Exposed =Window ,SecureContext ]interface { [BluetoothRemoteGATTServer SameObject ]readonly attribute BluetoothDevice device ;readonly attribute boolean connected ;Promise <BluetoothRemoteGATTServer >connect ();undefined disconnect ();Promise <BluetoothRemoteGATTService >getPrimaryService (BluetoothServiceUUID );service Promise <sequence <BluetoothRemoteGATTService >>getPrimaryServices (optional BluetoothServiceUUID ); };service
BluetoothRemoteGATTServer
属性device 是运行该服务器的设备。
connected 在该实例与
this.device 相连期间为 true。当 UA 在物理层面保持连接但对其他BluetoothRemoteGATTServer实例(位于其他全局对象)也建立连接时,该值可能为 false。
当没有 ECMAScript 代码能够再观察到某个 BluetoothRemoteGATTServer
实例 server 时,UA 应当运行
server.。
disconnect()
BluetoothDevice
实例保存在
navigator.bluetooth.[[deviceInstanceMap]]
中,这至少要等到导航释放该全局对象,或者关闭标签页或窗口销毁浏览上下文后才能发生。
BluetoothRemoteGATTServer
实例按下表所述,带有内部槽位:
| 内部槽位 | 初始值 | 描述(非规范性) |
|---|---|---|
[[activeAlgorithms]]
| new
|
包含与使用该服务器连接的每个算法对应的Promise。disconnect()
会清空该集合,以便算法可以判断其realm在运行期间是否曾被断开。
|
[[automatedGATTConnectionResponse]]
| "not-expected"
| 针对一次 GATT 连接尝试的模拟 GATT 连接响应码。 |
connect()
方法在被调用时,必须执行以下步骤:
-
如果this.
device.[[representedDevice]]为null,返回一个被拒绝的 promise,错误为“NetworkError”的DOMException。 -
如果 UA 当前正在使用蓝牙系统,它可以返回一个被拒绝的 promise,错误为“
NetworkError”的DOMException。实现可能能够避免该
NetworkError,但目前站点需要串行化对该 API 的使用,和/或为用户提供重试失败操作的方法。[Issue #188] -
令 promise 为一个新的 promise。
-
将 promise 添加到this.
[[activeAlgorithms]]。 -
并行运行以下步骤:
-
如果 global 的navigable 的 顶层可遍历对象具有模拟蓝牙适配器,则运行以下步骤:
-
触发一次 gatt 连接尝试事件,传入 global 的navigable 与this.
device。 -
如果this.
[[automatedGATTConnectionResponse]]为"not-expected",将其设为"expected"。 -
如果this.
[[automatedGATTConnectionResponse]]为"expected",则等待其改变。 -
令 response 为this.
[[automatedGATTConnectionResponse]]。 -
将this.
[[automatedGATTConnectionResponse]]设为"not-expected"。 -
如果 response 不为
0,执行以下子步骤:-
从this.
[[activeAlgorithms]]中移除 promise。 -
在给定 global 的Bluetooth 任务源上排队一个全局任务,以拒绝promise,错误为“
NetworkError”的DOMException,并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果this.
device.[[representedDevice]]尚无ATT 承载体,执行以下子步骤:-
尝试使用GAP 互操作性要求中的“连接建立”所述流程创建一个ATT 承载体。如果 promise 从this.
[[activeAlgorithms]]中被移除,则中止此次尝试。注意:如果未接收到可连接的广播,这些流程可能会无限等待。如果网站不再希望连接,应调用disconnect()。 -
如果此次尝试因 promise 从this.
[[activeAlgorithms]]中移除而被中止,则在给定 global 的Bluetooth 任务源上排队一个全局任务以拒绝promise,错误为“AbortError”的DOMException,并中止这些步骤。 -
如果此次尝试因其他原因失败,则在给定 global 的Bluetooth 任务源上排队一个全局任务以拒绝promise,错误为“
NetworkError”的DOMException,并中止这些步骤。 -
使用交换 MTU(Exchange MTU)流程来协商最大的支持 MTU。忽略此步骤中的任何错误。
-
UA 可以尝试使用BR/EDR 绑定流程或LE 绑定流程与远程设备建立绑定。
Note: 通常我们更希望由网站控制是否以及何时进行绑定,但 Core Bluetooth 平台 API 不提供让 UA 实现此控制的方式。拥有绑定比没有绑定更安全,因此本规范允许 UA 在可能的平台上机会性地创建绑定。这可能会导致在建立连接时(而不是访问受限特征值时)出现一个用户可见的配对对话框。
-
-
-
在给定 global 的Bluetooth 任务源上排队一个全局任务,以执行以下子步骤:
-
如果 promise 不在this.
[[activeAlgorithms]]中,拒绝promise,错误为“AbortError”的DOMException,回收该连接(位于 this.device.[[representedDevice]]),并中止这些步骤。 -
从this.
[[activeAlgorithms]]中移除 promise。 -
如果this.
device.[[representedDevice]]为null,拒绝promise,错误为“NetworkError”的DOMException,回收该连接(位于 this.device.[[representedDevice]]),并中止这些步骤。
-
-
-
返回 promise。
disconnect()
方法在被调用时,必须执行以下步骤:
-
清空
this.,以中止任何活动的[[activeAlgorithms]]connect()调用。 -
如果
this.为connectedfalse,中止这些步骤。 -
清理已断开连接的设备
this.device。 -
令 device 为
this.device.。[[representedDevice]] -
回收device 的连接。
-
如果 UA 内外部的非本 API 系统正在使用 device 的ATT 承载体,则中止本算法。
-
对于整个 UA 中的所有
BluetoothDevicedeviceObj:-
如果
deviceObj.不是与 device同一设备,则继续下一个 deviceObj。[[representedDevice]] -
如果
deviceObj.gatt.为connectedtrue,中止本算法。 -
如果
deviceObj.gatt.包含一次[[activeAlgorithms]]connect()调用的Promise,中止本算法。
-
-
销毁 device 的ATT 承载体。
BluetoothRemoteGATTServer
在执行期间被断开时失败,即便 UA 全程保持连接,且该BluetoothRemoteGATTServer
在结束前又重新连接。我们通过包装返回的Promise来实现这一点。
为了在 promise 周围创建一个 gattServer-连接检查包装器,UA 必须:
-
如果
gattServer.connected为true,将 promise 添加到gattServer.。[[activeAlgorithms]] -
对promise做出反应:
-
如果 promise 以值 result 得到满足,则:
-
如果 promise 在
gattServer.中,移除它并返回 result。[[activeAlgorithms]] -
否则,抛出
NetworkError。注意:抛出该错误是因为 gattServer 在主算法执行期间被断开。
-
-
如果 promise 以原因 error 被拒绝,则:
-
如果 promise 在
gattServer.中,移除它并抛出 error。[[activeAlgorithms]] -
否则,抛出
NetworkError。注意:抛出该错误是因为 gattServer 在主算法执行期间被断开。
-
-
getPrimaryService(service)
方法在被调用时,必须执行以下步骤:
-
如果
this.device.不为[[allowedServices]]"all",且 service 不在this.device.中,则返回一个被拒绝的 promise,错误为[[allowedServices]]SecurityError,并中止这些步骤。 -
返回 GetGATTChildren(attribute=
this.device,
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=this.device.,[[allowedServices]]
child type="GATT Primary Service")
getPrimaryServices(service)
方法在被调用时,必须执行以下步骤:
-
如果
this.device.不为[[allowedServices]]"all",且存在 service 且其不在this.device.中,则返回一个被拒绝的 promise,错误为[[allowedServices]]SecurityError,并中止这些步骤。 -
返回 GetGATTChildren(attribute=
this.device,
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=this.device.,[[allowedServices]]
child type="GATT Primary Service")
6.3. BluetoothRemoteGATTService
BluetoothRemoteGATTService
表示一个 GATT Service,即由若干特征值以及与其他服务的关系组成的集合,用于封装设备某一部分的行为。
[Exposed =Window ,SecureContext ]interface :BluetoothRemoteGATTService EventTarget { [SameObject ]readonly attribute BluetoothDevice device ;readonly attribute UUID uuid ;readonly attribute boolean isPrimary ;Promise <BluetoothRemoteGATTCharacteristic >getCharacteristic (BluetoothCharacteristicUUID );characteristic Promise <sequence <BluetoothRemoteGATTCharacteristic >>getCharacteristics (optional BluetoothCharacteristicUUID );characteristic Promise <BluetoothRemoteGATTService >getIncludedService (BluetoothServiceUUID );service Promise <sequence <BluetoothRemoteGATTService >>getIncludedServices (optional BluetoothServiceUUID ); };service BluetoothRemoteGATTService includes CharacteristicEventHandlers ;BluetoothRemoteGATTService includes ServiceEventHandlers ;
BluetoothRemoteGATTService
属性device 是表示该 GATT 服务所属的远程外围设备的
BluetoothDevice。
uuid 是该服务的 UUID,例如
'0000180d-0000-1000-8000-00805f9b34fb' 对应 心率(Heart Rate) 服务。
isPrimary
指示该服务的类型是主服务还是次级服务。
BluetoothRemoteGATTService
实例按下表所述带有内部槽位:
| 内部槽位 | 初始值 | 描述(非规范性) |
|---|---|---|
[[representedService]]
| <总在正文中设定> |
此对象所表示的Service;若该 Service
已被移除或以其他方式失效,则为 null。
|
BluetoothRemoteGATTService
的 Service service,UA 必须运行以下步骤:
-
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
令 result 为
BluetoothRemoteGATTService的新实例,其[[representedService]]槽位初始化为 service。 -
获取表示该设备的
BluetoothDevice,即 service 所在的设备,并令 device 为结果。 -
如果上一步抛出错误,则在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝promise 并附带该错误,然后中止这些步骤。
-
用 device 初始化 result.
device。 -
用 service 的 UUID 初始化 result.
uuid。 -
如果 service 是主服务,则将 result.
isPrimary设为true;否则设为false。 -
在给定 global 的 Bluetooth 任务源上排队一个全局任务,以解析promise,其值为 result。
-
-
返回 promise。
getCharacteristic(characteristic) 方法在此 Service 内检索一个
Characteristic。被调用时,必须返回:
GetGATTChildren(attribute=
this,
single=true,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")
getCharacteristics(characteristic) 方法在此 Service 内检索
Characteristic 列表。被调用时,必须返回:
GetGATTChildren(attribute=
this,
single=false,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")
getIncludedService(service) 方法在此 Service 内检索一个
Included
Service。被调用时,必须返回:
GetGATTChildren(attribute=
this,
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")
getIncludedServices(service) 方法在此 Service 内检索
Included Service
列表。被调用时,必须返回:
GetGATTChildren(attribute=
this,
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")
6.4. BluetoothRemoteGATTCharacteristic
BluetoothRemoteGATTCharacteristic
表示一个 GATT Characteristic,它是提供关于外围设备服务的进一步信息的基础数据单元。
[Exposed =Window ,SecureContext ]interface :BluetoothRemoteGATTCharacteristic EventTarget { [SameObject ]readonly attribute BluetoothRemoteGATTService service ;readonly attribute UUID uuid ;readonly attribute BluetoothCharacteristicProperties properties ;readonly attribute DataView ?value ;Promise <BluetoothRemoteGATTDescriptor >getDescriptor (BluetoothDescriptorUUID );descriptor Promise <sequence <BluetoothRemoteGATTDescriptor >>getDescriptors (optional BluetoothDescriptorUUID );descriptor Promise <DataView >readValue ();Promise <undefined >writeValue (BufferSource );value Promise <undefined >writeValueWithResponse (BufferSource );value Promise <undefined >writeValueWithoutResponse (BufferSource );value Promise <BluetoothRemoteGATTCharacteristic >startNotifications ();Promise <BluetoothRemoteGATTCharacteristic >stopNotifications (); };BluetoothRemoteGATTCharacteristic includes CharacteristicEventHandlers ;
BluetoothRemoteGATTCharacteristic
属性service 是该特征值所属的 GATT
服务。
uuid 是该特征值的 UUID,例如
'00002a37-0000-1000-8000-00805f9b34fb' 对应
心率测量(Heart Rate Measurement)特征值。
properties 保存该特征值的属性。
value
是当前缓存的特征值;当通过读取或通知/指示更新该特征值时,这个值会被更新。
BluetoothRemoteGATTCharacteristic
实例按下表所述带有内部槽位:
| 内部槽位 | 初始值 | 描述(非规范性) |
|---|---|---|
[[representedCharacteristic]]
| <总在正文中设定> |
此对象所表示的Characteristic;若该 Characteristic 已被移除或以其他方式失效,则为
null。
|
[[automatedCharacteristicReadResponse]]
| "not-expected"
| 针对一次 GATT 特征值读取尝试的模拟 GATT 特征值响应码。 |
[[automatedCharacteristicReadResponseData]]
| 空的字节序列 | 针对一次 GATT 特征值读取尝试的模拟 GATT 特征值响应数据。 |
[[automatedCharacteristicWriteResponse]]
| "not-expected"
| 针对一次 GATT 特征值写入尝试的模拟 GATT 特征值响应码。 |
[[automatedCharacteristicSubscribeToNotificationsResponse]]
| "not-expected"
| 针对一次订阅 GATT 特征值通知尝试的模拟 GATT 特征值响应码。 |
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]
| "not-expected"
| 针对一次取消订阅 GATT 特征值通知尝试的模拟 GATT 特征值响应码。 |
BluetoothRemoteGATTCharacteristic
的实例来表示特征值 characteristic,UA 必须运行以下步骤:
-
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
令 result 为
BluetoothRemoteGATTCharacteristic的新实例,其[[representedCharacteristic]]槽位初始化为 characteristic。 -
用出现 characteristic 的 Service 的表示实例,初始化 result.
service<。 -
用 characteristic 的 UUID 初始化 result.
uuid。 -
基于特征值创建一个
BluetoothCharacteristicProperties实例 characteristic,并令 properties 为其结果。 -
如果上一步返回错误,则在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝promise 并附带该错误,然后中止这些步骤。
-
将 result.
properties初始化为 properties。 -
将 result.
value初始化为null。如果可用,UA 可以将 result.value初始化为一个新的DataView,其封装了一个新的ArrayBuffer,包含最近一次从 characteristic 读取到的值。 -
在给定 global 的 Bluetooth 任务源上排队一个全局任务,以解析promise,其值为 result。
-
-
返回 promise。
getDescriptor(descriptor) 方法在此特征值内检索一个
Descriptor。被调用时,必须返回:
GetGATTChildren(attribute=
this,
single=true,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")
getDescriptors(descriptor) 方法在此特征值内检索
Descriptor 列表。被调用时,必须返回:
GetGATTChildren(attribute=
this,
single=false,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")
readValue()
方法被调用时,必须运行以下步骤:
-
如果this.
uuid被列入读取阻止列表,则返回一个被拒绝的 promise,错误为“SecurityError” 的DOMException,并中止这些步骤。 -
如果 gatt.
connected为false,则返回一个被拒绝的 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
令 characteristic 为this.
[[representedCharacteristic]]。 -
如果 characteristic 为
null,则返回一个被拒绝的 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
返回一个围绕新 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤:
-
如果 characteristic 的属性中未设置
Read位,则在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝promise,错误为“NotSupportedError” 的DOMException,并中止这些步骤。 -
如果 global 的navigable 的 顶层可遍历对象具有模拟蓝牙适配器,则运行以下步骤:
-
如果this.
[[automatedCharacteristicReadResponse]]不为"not-expected",则在给定 global 的 Bluetooth 任务源上排队一个全局任务以 拒绝 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
触发一个模拟的特征值事件,传入 global 的 navigable、this.
device、characteristic 和read。 -
将this.
[[automatedCharacteristicReadResponse]]设为"expected",并等待其改变。 -
令 response 为this.
[[automatedCharacteristicReadResponse]]。 -
将this.
[[automatedCharacteristicReadResponse]]设为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。
-
-
否则,令 buffer 为一个新的
ArrayBuffer,其中包含 this.[[automatedCharacteristicReadResponseData]]。
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,它可以在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。实现可能能够避免该
NetworkError,但目前站点需要串行化使用该 API,和/或为用户提供重试失败操作的方法。[Issue #188] -
使用特征值读取(Characteristic Value Read)流程中的任意子流程来获取 characteristic 的值,并令 buffer 为一个新的
ArrayBuffer,其中保存所取回的值。 错误按§ 6.7 错误处理进行处理。
-
-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则拒绝 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
如果上述子流程返回错误,则拒绝 promise 并附带该错误,中止这些步骤。
-
触发一个事件,名称为“
characteristicvaluechanged”,其bubbles属性初始化为true,目标为 this。
-
-
value: BufferSource,
response: string),
UA 必须执行以下步骤:
-
令 global 为 this 的相关全局对象。
-
如果 this.
uuid被列入写入阻止列表,则返回一个被拒绝的 promise,错误为“SecurityError” 的DOMException,并中止这些步骤。 -
令 bytes 为由 value 持有字节的拷贝。
-
如果 bytes 长度超过 512 字节(参见长属性值中的属性最大长度),则返回一个被拒绝的 promise,错误为“
InvalidModificationError” 的DOMException,并中止这些步骤。 -
如果 gatt.
connected为false,则返回一个被拒绝的 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
令 characteristic 为 this.
[[representedCharacteristic]]。 -
如果 characteristic 为
null,则返回一个被拒绝的 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
返回一个围绕新 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤。
-
断言:response 取值为 "required"、"never" 或 "optional" 之一。
-
如果 global 的navigable 的 顶层可遍历对象具有模拟蓝牙适配器,则运行以下步骤:
-
如果this.
[[automatedCharacteristicWriteResponse]]不为"not-expected",则在给定 global 的 Bluetooth 任务源上排队一个全局任务以 拒绝 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
触发一个模拟的特征值事件,传入 global 的 navigable、this.
device、characteristic、write和 bytes。 -
将this.
[[automatedCharacteristicWriteResponse]]设为"expected",并等待其改变。 -
令 response 为this.
[[automatedCharacteristicWriteResponse]]。 -
将this.
[[automatedCharacteristicWriteResponse]]设为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,它可以在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。实现可能能够避免该
NetworkError,但目前站点需要串行化使用该 API,和/或为用户提供重试失败操作的方法。[Issue #188] -
通过执行以下步骤将 bytes 写入 characteristic:
- 如果 response 为 "required"
- 使用 写特征值(Write Characteristic Value) 流程。
- 如果 response 为 "never"
- 使用 无响应写(Write Without Response) 流程。
- 否则
- 使用特征值写入(Characteristic Value Write)流程中的任意子流程组合。
-
-
在 global 上使用 Bluetooth 任务源排队一个全局任务以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则拒绝 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
如果上述流程返回错误,则拒绝 promise 并附带该错误,中止这些步骤。
-
将 this.
value设为一个新的DataView,其封装了一个新的ArrayBuffer,其中包含 bytes。 -
解析 promise,其值为
undefined。
-
-
writeValueWithResponse()
和
writeValueWithoutResponse()。
方法被调用时,必须返回:
writeValue(value)
WriteCharacteristicValue( this=
this,
value=value,
response="optional")
此方法仅用于向后兼容。新的实现不应实现此方法。[Issue #238]
writeValueWithResponse(value) 方法被调用时,必须返回:
WriteCharacteristicValue( this=
this,
value=value,
response="required")
writeValueWithoutResponse(value) 方法被调用时,
必须返回:
WriteCharacteristicValue( this=
this,
value=value,
response="never")
UA 必须维护一个从每个已知 GATT Characteristic 到一组 Bluetooth
对象的映射,该组被称为该特征值的活动通知上下文集合。
navigator.bluetooth
对象。当设备断开连接时,所有通知都会变为非活动状态。若站点希望在重新连接后继续接收通知,需要再次调用 startNotifications(),并且在
startNotifications()
生效前的间隙里不可避免会丢失部分通知。
startNotifications() 方法被调用时,必须运行以下步骤。关于接收通知的详细信息,参见
§ 6.6.4 响应通知与指示。
-
如果this.
uuid被列入读取阻止列表,则返回一个被拒绝的 promise,错误为“SecurityError” 的DOMException。 -
如果 gatt.
connected为false,则返回一个被拒绝的 promise,错误为“NetworkError” 的DOMException。 -
令 characteristic 为this.
[[representedCharacteristic]]。 -
如果 characteristic 为
null,则返回一个被拒绝的 promise,错误为“InvalidStateError” 的DOMException。 -
返回一个围绕新 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤。
-
如果 characteristic 的属性中既未设置
Notify位也未设置Indicate位,则在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为NotSupportedError,并中止这些步骤。 -
如果 characteristic 的活动通知上下文集合包含
navigator.bluetooth,则在给定 global 的 Bluetooth 任务源上排队一个全局任务以解析 promise,其值为this,并中止这些步骤。 -
如果 global 的navigable 的 顶层可遍历对象具有模拟蓝牙适配器,则运行以下步骤:
-
如果this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]不为"not-expected",则在给定 global 的 Bluetooth 任务源上排队一个全局任务以 拒绝 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
触发一个模拟的特征值事件,传入 global 的 navigable、this.
device、characteristic 与subscribe-to-notifications。 -
将this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]设为"expected",并等待其改变。 -
令 response 为this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]。 -
将this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]设为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。
-
-
否则,令 success 为
true。
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,它可以在给定 global 的 Bluetooth 任务源上排队一个全局任务以拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。实现可能能够避免该
NetworkError,但目前站点需要串行化使用该 API,和/或为用户提供重试失败操作的方法。[Issue #188] -
如果该特征值具有客户端特征值配置(Client Characteristic Configuration) 描述符,则使用任意特征值描述符(Characteristic Descriptors)流程,确保在 characteristic 的客户端特征值配置描述符中设置了
Notification或Indication位之一,并与 characteristic 的属性中的约束相匹配。UA 应避免同时设置两位;若两位均被设置,则必须对值变更事件去重。错误按§ 6.7 错误处理进行处理。注意:某些设备具有包含 Notify 或 Indicate 位的特征值属性,但却没有客户端特征值配置描述符。这些不符合标准的特征值往往无条件地发送通知或指示,因此本规范允许应用直接订阅其消息。 -
如果上述流程成功,则令 success 为
true。
-
-
如果 success 为
true,则将navigator.bluetooth加入 characteristic 的活动通知上下文集合。 -
在给定 global 的 Bluetooth 任务源上排队一个全局任务以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则拒绝 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
如果上述流程返回错误,则拒绝 promise 并附带该错误,中止这些步骤。
-
-
stopNotifications() 方法被调用时,必须返回 一个新的 promise
promise 并并行运行以下步骤:
-
令 characteristic 为
this.。[[representedCharacteristic]] -
如果 characteristic 为
null,返回一个被拒绝的 promise,错误为InvalidStateError,并中止这些步骤。 -
如果 characteristic 的 活动通知上下文集合(active notification context set) 包含
navigator.bluetooth, 则将其移除。-
如果 global 的 navigable 的 顶层可遍历对象的 模拟蓝牙适配器 非空,则运行以下步骤:
-
如果 this 的
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]不为"not-expected", 则在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
触发一个模拟的特征值事件,传入 global 的 navigable、this 的
device、 characteristic 以及unsubscribe-from-notifications。 -
将 this 的
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]设为"expected", 并等待其改变。 -
令 response 为 this 的
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]。 -
将 this 的
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]设为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果 characteristic 的 活动通知上下文集合 变为空,且该特征值具有 客户端特征值配置(Client Characteristic Configuration) 描述符,则 UA 应使用任意 特征值描述符(Characteristic Descriptors) 流程清除 characteristic 的 客户端特征值配置 描述符中的
Notification与Indication位。
-
-
-
在全局任务队列中排队一个任务,基于 Bluetooth 任务源,给定 this 的 相关全局对象,以解析 promise,其值为 this。
6.4.1. BluetoothCharacteristicProperties
每个 BluetoothRemoteGATTCharacteristic
都通过一个 BluetoothCharacteristicProperties
对象公开其特征值属性(characteristic properties)。这些属性表示在该特征值上哪些操作是有效的。
[Exposed =Window ,SecureContext ]interface {BluetoothCharacteristicProperties readonly attribute boolean ;broadcast readonly attribute boolean ;read readonly attribute boolean ;writeWithoutResponse readonly attribute boolean ;write readonly attribute boolean ;notify readonly attribute boolean ;indicate readonly attribute boolean ;authenticatedSignedWrites readonly attribute boolean ;reliableWrite readonly attribute boolean ; };writableAuxiliaries
BluetoothCharacteristicProperties 实例 characteristic,UA
必须运行以下步骤:
-
令 propertiesObj 为
BluetoothCharacteristicProperties的一个新实例。 -
令 properties 为 characteristic 的特征值属性。
-
根据 properties 中相应的比特,初始化 propertiesObj 的各属性:
Attribute Bit broadcastBroadcast readRead writeWithoutResponseWrite Without Response writeWrite notifyNotify indicateIndicate authenticatedSignedWritesAuthenticated Signed Writes -
如果特征值属性的 Extended Properties 位未设置,则将 propertiesObj.
reliableWrite和 propertiesObj.writableAuxiliaries初始化为false。否则,运行以下步骤:-
发现(Discover) Characteristic Extended Properties 描述符, 针对 characteristic 并读取其值到 extendedProperties。 错误按 § 6.7 错误处理 中所述进行处理。
Characteristic Extended Properties 尚不明确扩展属性对于某个特定 Characteristic 是否不可变。 如果不可变,UA 应被允许对其进行缓存。
-
如果上一步返回了错误,则返回该错误。
-
从 extendedProperties 的 Reliable Write 位初始化 propertiesObj.
reliableWrite。 -
从 extendedProperties 的 Writable Auxiliaries 位初始化 propertiesObj.
writableAuxiliaries。
-
-
返回 propertiesObj。
6.5. BluetoothRemoteGATTDescriptor
BluetoothRemoteGATTDescriptor
表示一个 GATT Descriptor,它为某个Characteristic 的值提供更多信息。
[Exposed =Window ,SecureContext ]interface { [BluetoothRemoteGATTDescriptor SameObject ]readonly attribute BluetoothRemoteGATTCharacteristic characteristic ;readonly attribute UUID uuid ;readonly attribute DataView ?value ;Promise <DataView >readValue ();Promise <undefined >writeValue (BufferSource ); };value
BluetoothRemoteGATTDescriptor
属性characteristic
是该描述符所属的 GATT 特征值。
uuid 是该特征值描述符的 UUID,例如
'00002902-0000-1000-8000-00805f9b34fb' 对应
Client Characteristic Configuration 描述符。
value
是当前缓存的描述符值。该值在读取描述符的值时会被更新。
BluetoothRemoteGATTDescriptor
实例创建时带有如下表所述的内部槽位(internal slots):
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[representedDescriptor]]
| <always set in prose> |
此对象所表示的Descriptor;若该描述符已被移除或以其他方式失效,则为 null。
|
[[automatedDescriptorReadResponse]]
| "not-expected"
| 针对一次 GATT 描述符读取尝试的模拟 GATT 描述符响应码。 |
[[automatedDescriptorReadResponseData]]
| 空的字节序列 | 针对一次 GATT 描述符读取尝试的模拟 GATT 描述符响应数据。 |
[[automatedDescriptorWriteResponse]]
| "not-expected"
| 针对一次 GATT 描述符写入尝试的模拟 GATT 描述符响应码。 |
BluetoothRemoteGATTDescriptor 的实例
用于表示一个 Descriptor descriptor,
UA 必须运行以下步骤:
-
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
令 result 为
BluetoothRemoteGATTDescriptor的新实例,其[[representedDescriptor]]槽位初始化为 descriptor。 -
用表示 descriptor 所在 Characteristic 的
BluetoothRemoteGATTCharacteristic实例初始化 result.characteristic。 -
用 descriptor 的 UUID 初始化 result.
uuid。 -
将 result.
value初始化为null。 如果可用,UA 可以将 result.value初始化为一个新的DataView,其封装了一个新的ArrayBuffer,包含最近一次从 descriptor 读取到的值。 -
在给定 this 的相关全局对象的前提下,在 Bluetooth 任务源上排队一个全局任务,以解析 promise,其值为 result。
-
-
返回 promise。
readValue() 方法被调用时,必须运行以下步骤:
-
令 gatt 为this.
characteristic.service.device.gatt。 -
如果this.
uuid被列入读取阻止列表,则返回一个被拒绝的 promise,错误为“SecurityError” 的DOMException。 -
如果 gatt.
connected为false,则返回一个被拒绝的 promise,错误为“NetworkError” 的DOMException。 -
令 descriptor 为this.
[[representedDescriptor]]。 -
如果 descriptor 为
null,则返回一个被拒绝的 promise,错误为“InvalidStateError” 的DOMException。 -
返回一个围绕新 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤:
-
如果 global 的navigable 的 top-level traversable 的 模拟蓝牙适配器 非空,则运行以下步骤:
-
如果this.
[[automatedDescriptorReadResponse]]不为"not-expected", 则在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
触发一个模拟的描述符事件,传入 global 的 navigable、this.
device、descriptor 和read。 -
将this.
[[automatedDescriptorReadResponse]]设为"expected", 并等待其改变。 -
令 response 为this.
[[automatedDescriptorReadResponse]]。 -
将this.
[[automatedDescriptorReadResponse]]设为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。
-
-
否则,令 buffer 为一个新的
ArrayBuffer,其中包含 this.[[automatedDescriptorReadResponseData]]。
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,它可以在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。实现可能能够避免该
NetworkError, 但目前站点需要串行化使用该 API,和/或为用户提供重试失败操作的方法。[Issue #188] -
使用 Read Characteristic Descriptors 或 Read Long Characteristic Descriptors 子流程获取 descriptor 的值,并令 buffer 为一个新的
ArrayBuffer,其中保存所取回的值。错误按 § 6.7 错误处理进行处理。
-
-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则拒绝 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
如果上述子流程返回错误,则拒绝 promise 并附带该错误,中止这些步骤。
-
-
writeValue(value) 方法被调用时,必须运行以下步骤:
-
令 gatt 为this.
characteristic.service.device.gatt。 -
如果this.
uuid被列入写入阻止列表,则返回一个被拒绝的 promise,错误为“SecurityError” 的DOMException。 -
令 bytes 为由 value 持有字节的拷贝。
-
如果 bytes 长度超过 512 字节(参见Long Attribute Values 中属性的最大长度),则返回一个被拒绝的 promise,错误为“
InvalidModificationError” 的DOMException。 -
如果 gatt.
connected为false,则返回一个被拒绝的 promise,错误为“NetworkError” 的DOMException。 -
令 descriptor 为this.
[[representedDescriptor]]。 -
如果 descriptor 为
null,则返回一个被拒绝的 promise,错误为“InvalidStateError” 的DOMException。 -
返回一个围绕新 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤。
-
如果 global 的navigable 的 top-level traversable 的 模拟蓝牙适配器 非空,则运行以下步骤:
-
如果this.
[[automatedDescriptorWriteResponse]]不为"not-expected", 则在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“InvalidStateError” 的DOMException,并中止这些步骤。 -
触发一个模拟的描述符事件,传入 global 的 navigable、this.
device、descriptor、write和 bytes。 -
将this.
[[automatedDescriptorWriteResponse]]设为"expected", 并等待其改变。 -
令 response 为this.
[[automatedDescriptorWriteResponse]]。 -
将this.
[[automatedDescriptorWriteResponse]]设为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,它可以在给定 global 的 全局任务队列中,基于 Bluetooth 任务源 拒绝 promise,错误为“
NetworkError” 的DOMException,并中止这些步骤。实现可能能够避免该
NetworkError, 但目前站点需要串行化使用该 API,和/或为用户提供重试失败操作的方法。[Issue #188] -
使用 Write Characteristic Descriptors 或 Write Long Characteristic Descriptors 子流程将 bytes 写入 descriptor。错误按 § 6.7 错误处理进行处理。
-
-
在给定 global 的 Bluetooth 任务源上排队一个全局任务以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则拒绝 promise,错误为“NetworkError” 的DOMException,并中止这些步骤。 -
如果上述子流程返回错误,则拒绝 promise 并附带该错误,中止这些步骤。
-
将this.
value设为一个新的DataView,其封装了一个新的ArrayBuffer,其中包含 bytes。 -
解析 promise,其值为
undefined。
-
-
6.6. 事件
6.6.1. Bluetooth 树
Bluetooth 树 指的是
navigator.bluetooth
以及实现
BluetoothDevice、
BluetoothRemoteGATTService、
BluetoothRemoteGATTCharacteristic
或 BluetoothRemoteGATTDescriptor
接口并参与到一棵树中的对象的统称。
-
navigator.bluetooth的子节点是表示位于allowedDevices列表中的设备的BluetoothDevice对象;该列表来自 "bluetooth" 的 额外权限数据,对应于navigator.bluetooth的相关设置对象,顺序未指定。 -
BluetoothDevice的子节点是其 GATT 服务器 上表示主(Primary)与次级(Secondary) Service 的BluetoothRemoteGATTService对象,其 UUID 位于来源(origin)与设备的allowedServices列表中。主服务的顺序必须与 按服务 UUID 发现主服务 过程返回的顺序一致,但不同 UUID 的主服务与所有次级服务可以以任意顺序排列。 -
BluetoothRemoteGATTService的子节点是表示其各个 Characteristic 的BluetoothRemoteGATTCharacteristic对象。特征值的顺序必须与 按 UUID 发现特征值过程返回的顺序一致, 但不同 UUID 的特征值可以以任意顺序排列。 -
BluetoothRemoteGATTCharacteristic的子节点是表示其各个描述符的BluetoothRemoteGATTDescriptor对象,顺序与 发现全部特征值描述符 过程返回的顺序一致。
6.6.2. 事件类型
-
advertisementreceived -
当从该设备接收到广播事件时,
在
BluetoothDevice上触发。 availabilitychanged-
当整个蓝牙系统对 UA 变为可用或不可用时,
在
navigator.bluetooth上触发。 -
characteristicvaluechanged -
当
BluetoothRemoteGATTCharacteristic的值发生变化时触发, 可能源于一次 读取请求,或 值变更通知/指示。 -
gattserverdisconnected -
当一个活动的 GATT 连接丢失时,
在
BluetoothDevice上触发。 -
serviceadded -
当一个新的
BluetoothRemoteGATTService在远程设备上被发现后、刚被添加到 Bluetooth 树 时触发。 -
servicechanged -
当
BluetoothRemoteGATTService的状态发生变化时触发。 这包括服务中任何被添加或移除的特征值和/或描述符,以及来自远程设备的 Service Changed 指示。 -
serviceremoved -
当
BluetoothRemoteGATTService从其设备上被移除时触发,就在它从 Bluetooth 树中被删除之前。
6.6.3. 响应断开连接
BluetoothDevice
deviceObj,在给定 deviceObj 的相关全局对象的前提下,基于
Bluetooth 任务源
排队一个全局任务以执行以下步骤:
-
如果
deviceObj.与 device 不是同一设备,则中止这些步骤。[[representedDevice]] -
如果
!deviceObj.gatt., 则中止这些步骤。connected -
清理已断开连接的设备 deviceObj。
-
将
deviceObj.gatt.设为connectedfalse。 -
清空
deviceObj.gatt.。[[activeAlgorithms]] -
将
deviceObj.gatt.设为[[automatedGATTConnectionResponse]]"not-expected"。 -
令 context 为
deviceObj.。[[context]] -
从
context.中移除所有键位于[[attributeInstanceMap]]deviceObj.范围内的条目。[[representedDevice]] -
对于 deviceObj 的 realm 中的每个
BluetoothRemoteGATTServiceservice,将service.设为[[representedService]]null。 -
对于 deviceObj 的 realm 中的每个
BluetoothRemoteGATTCharacteristiccharacteristic,执行以下子步骤:-
令 notificationContexts 为
characteristic.的活动通知上下文集合。[[representedCharacteristic]] -
从 notificationContexts 中移除 context。
-
如果 notificationContexts 变为空,并且仍然存在到
deviceObj.的 ATT 承载, 且 characteristic 具有 客户端特征值配置(Client Characteristic Configuration) 描述符,则 UA 应使用任意 特征值描述符流程清除 characteristic 的 客户端特征值配置 描述符中的[[representedDevice]]Notification与Indication位。 -
将
characteristic.设为[[representedCharacteristic]]null。
-
-
对于 deviceObj 的 realm 中的每个
BluetoothRemoteGATTDescriptordescriptor,将descriptor.设为[[representedDescriptor]]null。 -
触发一个事件,名称为
gattserverdisconnected, 其bubbles属性初始化为true,在deviceObj上触发。注意:该事件不会在BluetoothRemoteGATTServer上触发。
6.6.4. 响应通知与指示
-
对于特征值的活动通知上下文集合中的每个 bluetoothGlobal,在给定 bluetoothGlobal 的相关全局对象的前提下,基于 Bluetooth 任务源 排队一个全局任务以执行以下子步骤:
-
令 characteristicObject 为以 bluetoothGlobal 为根的 Bluetooth 树中,表示该 Characteristic 的
BluetoothRemoteGATTCharacteristic。 -
如果
characteristicObject .service.device.gatt.为connectedfalse,则中止这些子步骤。 -
将
characteristicObject.value设为一个新的DataView, 其封装一个新的ArrayBuffer, 其中保存该Characteristic 的新值。 -
触发一个事件,名称为
characteristicvaluechanged, 其bubbles属性初始化为true,在 characteristicObject 上触发。
-
6.6.5. 响应服务变更
-
令 removedAttributes 为 Service Changed 特征值所指示范围内,UA 在该指示之前已发现的属性列表。
-
使用 主服务发现(Primary Service Discovery)、 关系发现(Relationship Discovery)、 特征值发现(Characteristic Discovery) 和 特征值描述符发现(Characteristic Descriptor Discovery) 过程重新发现 Service Changed 特征值所指示范围内的属性。若 UA 能够证明跳过全部或部分范围的发现不会影响下面将触发的事件,则可以跳过。
-
令 addedAttributes 为上一步中发现的属性列表。
-
如果在忽略特征值与描述符的值后,具有相同定义(参见 服务互操作性要求)的某个属性同时出现在 removedAttributes 与 addedAttributes 中,则将其从两者中移除。
给定如下设备状态:- 状态 1
-
-
Service A
- Characteristic C: value
[1, 2, 3]
- Characteristic C: value
- Service B
-
Service A
- 状态 2
-
-
Service A
- Characteristic C: value
[3, 2, 1]
- Characteristic C: value
- Service B
-
Service A
- 状态 3
-
-
Service A
- Characteristic D: value
[3, 2, 1]
- Characteristic D: value
- Service B
-
Service A
- 状态 4
-
-
Service A
- Characteristic C: value
[1, 2, 3]
- Characteristic C: value
-
Service B
- Include Service A
-
Service A
从状态 1 到 2 的转换,使得服务 A 具有“相同的定义(忽略特征值与描述符的值)”,因此它会从 removedAttributes 和 addedAttributes 中被移除,也就不会触发任何
servicechanged事件。从状态 1 到 3 的转换,使得服务 A 的定义不同,因为 服务定义 包含其特征值定义,所以它会同时保留在 removedAttributes 与 addedAttributes 中。随后在步骤 8,该服务被移动到 changedServices,从而只触发一个
servicechanged事件,而不是同时触发serviceadded与serviceremoved。 步骤 9 也会将服务 A 添加到 changedServices 中,因为特征值 C 被移除而特征值 D 被添加。从状态 1 到 4 的转换与 1→3 类似。服务 B 在 步骤 8 被移动到 changedServices, 但由于没有特征值或描述符发生变化,所以在 步骤 9 中不会被重复添加。
-
令 invalidatedAttributes 为 removedAttributes 中但不在 addedAttributes 中的属性。
-
对于 UA 中的每个 环境设置对象 settings,在其 对应的事件循环上 排队一个任务以执行以下子步骤:
-
对于每个其相关设置对象为 settings 的
BluetoothRemoteGATTServiceservice,若service.位于 invalidatedAttributes 中,则将其设为[[representedService]]null。 -
对于每个其相关设置对象为 settings 的
BluetoothRemoteGATTCharacteristiccharacteristic,若characteristic.位于 invalidatedAttributes 中,则将其设为[[representedCharacteristic]]null。 -
对于每个其相关设置对象为 settings 的
BluetoothRemoteGATTDescriptordescriptor,若descriptor.位于 invalidatedAttributes 中,则将其设为[[representedDescriptor]]null。 -
令 global 为 settings 的 全局对象。
-
从
global.navigator.bluetooth.中移除每个表示位于 invalidatedAttributes 中的属性的条目。[[attributeInstanceMap]]
-
-
令 changedServices 为一个 Service 集合,初始为空。
-
如果某个相同的 Service 同时出现在 removedAttributes 与 addedAttributes 中,则将其从两者中移除,并添加到 changedServices 中。
-
对于 removedAttributes 或 addedAttributes 中的每个 Characteristic 与 Descriptor,将其从原列表中移除,并将其父 Service 添加到 changedServices 中。
注意:从此之后,removedAttributes 与 addedAttributes 仅包含 Service。 -
如果 addedAttributes 中的某个 Service 在之前的任一调用
getPrimaryService、getPrimaryServices、getIncludedService或getIncludedServices(若当时已经存在)时都不会被返回,则 UA 可以从 addedAttributes 中移除该 Service。 -
令 changedDevices 为包含 removedAttributes、 addedAttributes 与 changedServices 中任意 Service 的 蓝牙设备 集合。
-
对于每个与 changedDevices 中的设备相连的
BluetoothDevicedeviceObj,在给定其相关全局对象的前提下,基于 Bluetooth 任务源 排队一个全局任务以执行以下步骤:-
对于 removedAttributes 中的每个 Service service:
-
如果
deviceObj.为[[allowedServices]]"all"或包含该服务的 UUID,则在表示该 Service 的BluetoothRemoteGATTService上,触发一个事件,名称为serviceremoved, 其bubbles属性初始化为true。
-
-
对于 addedAttributes 中的每个 Service,如果
deviceObj.为[[allowedServices]]"all"或包含该服务的 UUID,则将表示该 Service 的BluetoothRemoteGATTService添加到Bluetooth 树,随后 触发一个事件,名称为serviceadded, 其bubbles属性初始化为true,在该BluetoothRemoteGATTService上触发。 -
对于 changedServices 中的每个 Service,如果
deviceObj.为[[allowedServices]]"all"或包含该服务的 UUID,则 触发一个事件,名称为servicechanged, 其bubbles属性初始化为true,在表示该 Service 的BluetoothRemoteGATTService上触发。
-
6.6.6. IDL 事件处理器
[SecureContext ]interface mixin {CharacteristicEventHandlers attribute EventHandler oncharacteristicvaluechanged ; };
oncharacteristicvaluechanged 是 事件处理程序 IDL 属性,用于
characteristicvaluechanged
事件类型。
[SecureContext ]interface mixin {BluetoothDeviceEventHandlers attribute EventHandler onadvertisementreceived ;attribute EventHandler ongattserverdisconnected ; };
onadvertisementreceived
是事件处理程序 IDL 属性,用于 advertisementreceived
事件类型。
ongattserverdisconnected
是事件处理程序 IDL 属性,用于 gattserverdisconnected
事件类型。
[SecureContext ]interface mixin {ServiceEventHandlers attribute EventHandler onserviceadded ;attribute EventHandler onservicechanged ;attribute EventHandler onserviceremoved ; };
onserviceadded 是事件处理程序 IDL 属性,用于 serviceadded
事件类型。
onservicechanged 是事件处理程序 IDL 属性,用于 servicechanged
事件类型。
onserviceremoved 是事件处理程序 IDL 属性,用于 serviceremoved
事件类型。
6.7. 错误处理
错误响应(Error Response),UA
必须执行以下步骤:
-
如果流程超时, 或 配置文件基础中描述的 ATT 承载缺失或因任何原因被终止, 则从该步骤返回一个
NetworkError, 并中止这些步骤。 -
根据
Error Code的不同,采取如下动作:Invalid PDUInvalid OffsetAttribute Not FoundUnsupported Group Type-
这些错误码表明在协议层发生了意外情况,可能是 UA 或设备的缺陷。从该步骤返回
NotSupportedError。 Invalid Handle-
从该步骤返回
InvalidStateError。 Invalid Attribute Value Length-
从该步骤返回
InvalidModificationError。 Attribute Not Long-
如果在未使用“Long”子流程的情况下收到该错误码,则可能表示设备缺陷。从该步骤返回
NotSupportedError。否则,重试该步骤且不使用“Long”子流程。若因写入值过长而无法做到,则从该步骤返回
InvalidModificationError。 Insufficient AuthenticationInsufficient EncryptionInsufficient Encryption Key Size-
UA 应尝试提升连接的安全级别。若尝试失败或 UA 不支持更高的安全级别,则从该步骤返回
SecurityError; 否则,在新的更高安全级别上重试该步骤。 Insufficient Authorization-
从该步骤返回
SecurityError。 Application Error-
如果 GATT 流程是写入操作(Write),则从该步骤返回
InvalidModificationError; 否则,从该步骤返回NotSupportedError。 Read Not PermittedWrite Not PermittedRequest Not SupportedPrepare Queue FullInsufficient ResourcesUnlikely Error- 其他任何情况
-
从该步骤返回
NotSupportedError。
7. UUID
typedef DOMString ;UUID
UUID 字符串表示一个 128 位的
[RFC4122] UUID。
有效
UUID
是一个匹配 [ECMAScript]
正则表达式 /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ 的字符串。
即,有效 UUID 必须为小写,且不使用蓝牙标准定义的 16 位或 32
位缩写。
本规范中函数与属性返回的所有 UUID 必须是有效 UUID。
如果本规范中的某个函数的参数类型为 UUID 或包含
UUID 属性的字典,而传入的任何
UUID 槽位不是有效 UUID,
则该函数必须返回一个被拒绝的 promise,
错误为 TypeError,并中止其余步骤。
BluetoothUUID.canonicalUUID(alias)
函数,用于将 16 位或 32 位的蓝牙UUID 别名映射为其 128
位形式。
7.1. 标准化 UUID
蓝牙 SIG 在 [BLUETOOTH-ASSIGNED] 维护一个用于标识服务、特征值、描述符及其他实体的 UUID 注册表。本节为脚本提供按名称查找这些 UUID 的方式,从而无需在每个应用中重复。
有效名称 是一个匹配
[ECMAScript]
正则表达式 /^[a-z0-9_-.]+$/ 的字符串。
[Exposed =Window ]interface {BluetoothUUID static UUID getService ((DOMString or unsigned long ));name static UUID getCharacteristic ((DOMString or unsigned long ));name static UUID getDescriptor ((DOMString or unsigned long ));name static UUID canonicalUUID ([EnforceRange ]unsigned long ); };alias typedef (DOMString or unsigned long )BluetoothServiceUUID ;typedef (DOMString or unsigned long )BluetoothCharacteristicUUID ;typedef (DOMString or unsigned long )BluetoothDescriptorUUID ;
当调用静态方法 BluetoothUUID. 时,必须返回由 16 位或 32 位 UUID 别名 alias
所表示的
128 位 UUID。
canonicalUUID(alias)
00000000-0000-1000-8000-00805f9b34fb" 的最高 32 位替换为别名的比特。
例如,canonicalUUID(0xDEADBEEF) 返回
"deadbeef-0000-1000-8000-00805f9b34fb"。
BluetoothServiceUUID 表示 16 位与 32 位 UUID 别名、
有效 UUID 以及来自
GATT 指定服务键的
有效名称;或等价地,表示不会导致
BluetoothUUID.getService()
抛出异常的取值。
BluetoothCharacteristicUUID 表示 16 位与 32 位
UUID 别名、
有效 UUID 以及来自
GATT 指定特征值键的
有效名称;或等价地,表示不会导致
BluetoothUUID.getCharacteristic()
抛出异常的取值。
BluetoothDescriptorUUID 表示 16 位与 32 位 UUID
别名、
有效 UUID 以及来自
GATT
指定描述符键的
有效名称;或等价地,表示不会导致
BluetoothUUID.getDescriptor()
抛出异常的取值。
-
如果 name 是
unsigned long,则返回BluetoothUUID.canonicalUUID(name),并中止这些步骤。 -
如果 name 是有效 UUID, 则返回 name 并中止这些步骤。
-
如果 name 是有效名称, 且在 GATT assigned numbers 中映射到一个有效 UUID, 则令 alias 为其指定编号,并返回
BluetoothUUID.canonicalUUID(alias)。 -
否则,抛出
TypeError。
当调用静态方法 BluetoothUUID. 时,必须返回
ResolveUUIDName(
getService(name)name,
GATT 指定服务)。
当调用静态方法 BluetoothUUID. 时,必须返回
ResolveUUIDName(
getCharacteristic(name)name,
GATT 指定特征值)。
当调用静态方法 BluetoothUUID. 时,必须返回
ResolveUUIDName(
getDescriptor(name)name,
GATT
指定描述符)。
BluetoothUUID.getService(" cycling_power")
返回 "00001818-0000-1000-8000-00805f9b34fb"。
返回
BluetoothUUID.getService("00001801-0000-1000-8000-00805f9b34fb")"00001801-0000-1000-8000-00805f9b34fb"。
会抛出 BluetoothUUID.getService("unknown-service")TypeError。
返回 BluetoothUUID.getCharacteristic("ieee_11073-20601_regulatory_certification_data_list")"00002a2a-0000-1000-8000-00805f9b34fb"。
返回 BluetoothUUID.getDescriptor("gatt.characteristic_presentation_format")"00002904-0000-1000-8000-00805f9b34fb"。
7.2. GATT 指定编号
本规范为 GATT 指定编号提供了便于阅读的人类可读名称,以提升使用标准化 GATT 服务、特征值与描述符的开发者的可读性。GATT 指定编号文件存放在 https://github.com/WebBluetoothCG/registries 仓库中。
-
获取 url,并令 contents 为其主体,以 UTF-8 解码。
-
令 lines 为将 contents 按
'\n'分割后的结果。 -
令 result 为空映射。
-
对 lines 中的每一行 line,执行以下子步骤:
-
返回 result。
GATT 指定服务是在 解析 GATT 指定编号于 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt 的结果。 UA 应定期重新获取该文件,但频率未作规定。
GATT 指定特征值是在 解析 GATT 指定编号于 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_characteristics.txt 的结果。 UA 应定期重新获取该文件,但频率未作规定。
GATT 指定描述符是在 解析 GATT 指定编号于 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_descriptors.txt 的结果。 UA 应定期重新获取该文件,但频率未作规定。
8. 广告数据过滤器
广告数据过滤器表示一种匹配制造商数据或服务数据的方式。
-
令 words 为 input 在 严格分割后的结果,分隔符为
/。 -
如果 words 的长度不等于
2,返回错误并中止这些步骤。 -
如果 words[0] 的长度不等于 words[1] 的长度,返回错误并中止这些步骤。
-
令 prefixData 为 words[0]。
-
令 prefixMask 为 words[1]。
-
如果 prefixData 或 prefixMask 不是小写 ASCII 十六进制数字序列,返回错误。
-
令 prefixIndex 为
0。 -
令 dataList 为空列表。
-
令 maskList 为空列表。
-
当 prefixIndex 小于 prefixData 的长度时,执行以下子步骤:
-
令 data 为将 prefixData 中索引 prefixIndex 与
prefixIndex + 1处的字符解释为十六进制数的结果。 -
令 mask 为将 prefixMask 中索引 prefixIndex 与
prefixIndex + 1处的字符解释为十六进制数的结果。 -
将 data 追加到 dataList。
-
将 mask 追加到 maskList。
-
将 prefixIndex 设为
|prefixIndex| + 2。
-
-
令 result 为一个新的
BluetoothDataFilterInit字典。 -
将 result[
dataPrefix] 设为以 dataList 构造的Uint8Array。 -
将 result[
mask] 设为以 maskList 构造的Uint8Array。 -
返回 result。
9. 阻止列表
本规范依赖 https://github.com/WebBluetoothCG/registries 仓库中的阻止列表文件,以限制网站可访问的 GATT 属性与制造商数据的集合。
有效公司标识符字符串是小写 ASCII
十六进制数字的序列,其长度大于
0 且小于 5。公司标识符的官方列表可在
Bluetooth Assigned Numbers 网站找到。
BluetoothDataFilterInit
列表的映射,或一个错误,由以下算法产生:
-
获取 url,并令 contents 为其主体,以 UTF-8 解码。
-
令 lines 为在 contents 上调用
split(separator, limit)且分隔符为'\n'的结果。 -
令 result 为空映射。
-
对 lines 中的每一行 line,执行以下子步骤:
-
如果 line 为空或其首字符为
'#',继续到下一行。 -
令 regExp 为以 'manufacturer\ ([0-9a-f]+)\ ([0-9a-f]+\/[0-9a-f]+)' 构造的
RegExp。 -
令 matchResult 为调用 regExp.
exec(string)于 line 的结果;若 matchResult 为null或其长度不等于3,则返回错误。 -
若 matchResult[1] 是有效公司标识符字符串,则令 companyIdentifierStr 为 matchResult[1];否则返回错误。
-
令 companyIdentifier 为将 companyIdentifierStr 解释为十六进制数的结果。
-
令 dataPrefixStr 为 matchResult[2]。
-
如果 companyIdentifier 不在 result 中,则设 result[companyIdentifier] 为一个空列表。
-
若不是错误,则令 dataFilter 为在 dataPrefixStr 处解析广告数据过滤器的结果;否则返回错误。
-
将 dataFilter 追加到 result[companyIdentifier]。
-
-
返回 result。
-
获取 url,并令 contents 为其主体,以 UTF-8 解码。
-
令 lines 为将 contents 按
'\n'分割后的结果。 -
令 result 为空映射。
-
对 lines 中的每一行 line,执行以下子步骤:
-
返回 result。
GATT 阻止列表 是在 解析 GATT 阻止列表于 https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt 的结果。 制造商数据阻止列表 是在 解析制造商数据阻止列表于 https://github.com/WebBluetoothCG/registries/blob/master/manufacturer_data_blocklist.txt 的结果。 UA 应定期重新获取阻止列表,但频率未作规定。
若 UUID 的 GATT 阻止列表 值为错误,或该 UUID 在
GATT 阻止列表 中映射到
"exclude",则该 UUID 为
被阻止。
若 UUID 的 GATT 阻止列表 值为错误,或该 UUID 在
GATT 阻止列表 中映射到
"exclude" 或 "exclude-reads",则该 UUID
被阻止读取。
若 UUID 的 GATT 阻止列表 值为错误,或该 UUID 在
GATT 阻止列表 中映射到
"exclude" 或 "exclude-writes",则该 UUID
被阻止写入。
blocked 时,制造商数据 manufacturerData 是被阻止的制造商数据:
-
如果 制造商数据阻止列表 的值为错误,返回
blocked。 -
令 manufacturerBlocklist 为 制造商数据阻止列表 的值。
-
令 companyIdentifier 为 manufacturerData 的公司标识符。
-
如果 companyIdentifier 不在 manufacturerBlocklist 中,返回
unblocked。 -
对 manufacturerBlocklist[companyIdentifier] 中的每个 dataFilter,执行以下子步骤:
-
如果 manufacturerData 的广告数据匹配 dataFilter,返回
blocked。
-
-
返回
unblocked。
blocked 时,制造商数据过滤器 manufacturerDataFilter 是被阻止的制造商数据过滤器:
-
如果 制造商数据阻止列表 的值为错误,返回
blocked。 -
令 manufacturerBlocklist 为 制造商数据阻止列表 的值。
-
令 companyIdentifier 为 manufacturerDataFilter["
companyIdentifier"]。 -
如果 companyIdentifier 不在 manufacturerBlocklist 中,返回
unblocked。 -
对 manufacturerBlocklist[companyIdentifier] 中的每个 dataFilter,执行以下子步骤:
-
如果 manufacturerDataFilter 是 严格子集 于 dataFilter,则返回
blocked。
-
-
返回
unblocked。
10. 对 Navigator 接口的扩展
[SecureContext ]partial interface Navigator { [SameObject ]readonly attribute Bluetooth bluetooth ; };
每个 Navigator
都有一个关联的
Bluetooth,它是一个
Bluetooth
对象。在创建 Navigator
对象时,其关联的
Bluetooth必须被设为在该 Navigator
对象的相关领域中创建的新 Bluetooth
对象。
Navigator
的
bluetooth 取值步骤为返回 this 的 关联的 Bluetooth。
11. 集成
11.1. 权限策略
本规范定义了一个策略控制的特性,其标识符为
标记 "bluetooth",
用于控制是否允许 bluetooth
属性所暴露的方法在 Navigator
对象上被使用。
该特性的默认允许列表为
["self"]。
12. 自动化测试
就用户代理自动化与应用测试而言,本文档对 [WebDriver-BiDi] 规范进行了扩展。
Web Bluetooth API 及其扩展规范给测试作者带来挑战,因为要充分验证这些接口需要能以可预期方式响应的物理硬件设备。为解决这一挑战,本文档定义了一系列 WebDriver-BiDi 扩展命令,用于定义与控制模拟的外设与广播,使其表现如同物理设备外设及其广播。这些模拟外设与广播代表具有特定属性的设备,其读数可由用户完全定义。
每个顶层可遍历对象可以有一个模拟 Bluetooth 适配器,即软件定义的 Bluetooth 适配器,拥有一组已发现的模拟 Bluetooth 设备,并可承担如 Central 等角色。
每个模拟
Bluetooth 适配器都有一个模拟 Bluetooth 设备映射,它是从 Bluetooth 地址 字符串到模拟
Bluetooth 设备的有序映射。
每个模拟 Bluetooth 适配器有一个适配器状态,是描述适配器当前状态的字符串枚举。可用的枚举值为:
-
"powered-on"
-
"powered-off"
-
"absent"
每个模拟 Bluetooth 适配器有一个低功耗支持状态,这是一个布尔值,描述该适配器是否支持 Bluetooth Low Energy。
模拟 Bluetooth 设备是软件定义的Bluetooth 设备,其行为类似物理设备,可附加到模拟 Bluetooth 适配器, 可具有如制造商特定数据与服务 UUID等关联属性, 并具有一个模拟 GATT 服务映射,它是从 Bluetooth UUID 字符串到模拟 GATT 服务的有序映射。
模拟 GATT 服务是软件定义的Service,属于一个 模拟 Bluetooth 设备,具有 UUID 属性,在 Bluetooth 缓存中为已知存在,并具有一个模拟 GATT 特征值映射, 它是从 Bluetooth UUID 字符串到模拟 GATT 特征值的有序映射。
模拟 GATT 特征值是软件定义的Characteristic,属于一个 模拟 GATT 服务,具有 UUID 属性与特征值属性属性, 在 Bluetooth 缓存中为已知存在,并具有一个模拟 GATT 描述符映射, 它是从 Bluetooth UUID 字符串到模拟 GATT 描述符的有序映射。
模拟 GATT 特征值属性是软件定义的特征值属性,属于一个 模拟 GATT 特征值,并在 Bluetooth 缓存中为已知存在。
模拟 GATT 描述符是软件定义的Descriptor,属于一个 模拟 GATT 特征值,具有 UUID 属性,并在 Bluetooth 缓存中为已知存在。
CDDL 片段使用 “text” 类型而不是 “browsingContext.BrowsingContext”,以便对 CDDL 片段进行独立的程序化处理。目前,不能引用其他模块。
12.1. 定义
bluetooth.BluetoothUuid= text;bluetooth.BluetoothManufacturerData= {key: uint,data: tstr };bluetooth.CharacteristicProperties= { ?broadcast: bool, ?read: bool, ?writeWithoutResponse: bool, ?write: bool, ?notify: bool, ?indicate: bool, ?authenticatedSignedWrites: bool, ?extendedProperties: bool }
key- 公司标识符代码(Company Identifier Code)。
data- 制造商数据的字节序列,以 base64 编码。
12.2. bluetooth 模块
bluetooth 模块包含用于管理远端 Bluetooth 行为的命令。
12.2.1. 类型
12.2.1.1. bluetooth.RequestDevice 类型
bluetooth.RequestDevice = text
bluetooth.RequestDevice 是请求设备提示框中单个设备的标识符。
设备提示是一个由设备提示 id(字符串)与设备集合(由 集合构成,元素为 BluetoothDevice
对象)的元组。它表示一个允许用户选择Bluetooth 设备的提示。
12.2.1.2. bluetooth.RequestDeviceInfo 类型
bluetooth.RequestDeviceInfo = { id : bluetooth.RequestDevice , name : text/ null, }
bluetooth.RequestDeviceInfo 表示请求设备提示框中的单个设备。
BluetoothDevice
device,序列化设备:
12.2.1.3. bluetooth.RequestDevicePrompt 类型
bluetooth.RequestDevicePrompt = text
bluetooth.RequestDevicePrompt 是单个提示框的标识符。
远端拥有一个可导航到设备提示的映射,它是一个映射,键为可导航 id,值为设备提示。
-
令 promptMap 为可导航到设备提示的映射。
-
如果 promptMap[navigableId]不存在:
-
返回错误,其错误码为 no such prompt。
-
-
令 prompt 为 可导航到设备提示的映射[navigableId]。
-
如果 prompt 的设备提示 id不是 promptId:
-
返回错误,其错误码为 no such prompt。
-
-
返回成功,其数据为 prompt。
12.2.1.4. bluetooth.ScanRecord 类型
bluetooth.ScanRecord = { ? name : text, ? uuids : [ * bluetooth.BluetoothUuid ], ? appearance : number, ? manufacturerData : [ * bluetooth.BluetoothManufacturerData ], }
bluetooth.ScanRecord 表示由Bluetooth 设备发送的广播包数据。
name- 为Bluetooth 设备的本地名称或其前缀。
uuids- 列出该扫描记录所指示的Bluetooth 设备的 GATT 服务器所支持的服务 UUID。
appearance- 为Appearance,对应于
gap.appearance特征值定义的值之一。 manufacturerDataBluetoothManufacturerData的列表,将unsigned short的公司标识符代码映射到以 base64 编码的制造商数据字节序列。
12.2.2. 错误
本规范在 WebDriver BiDi 的错误码集合基础上,扩展了以下附加错误码:
- no such device
- 尝试引用未知的
BluetoothDevice。 - no such prompt
- 尝试引用未知的设备提示。
12.2.3. 命令
BluetoothCommand = ( bluetooth.HandleRequestDevicePrompt // bluetooth.SimulateAdapter // bluetooth.DisableSimulation // bluetooth.SimulatePreconnectedPeripheral // bluetooth.SimulateAdvertisement // bluetooth.SimulateGattConnectionResponse // bluetooth.SimulateGattDisconnection // bluetooth.SimulateService // bluetooth.SimulateCharacteristic // bluetooth.SimulateCharacteristicResponse // bluetooth.SimulateDescriptor // bluetooth.SimulateDescriptorResponse )
12.2.3.1. bluetooth.handleRequestDevicePrompt 命令
bluetooth.HandleRequestDevicePrompt = ( method : "bluetooth.handleRequestDevicePrompt" , params : bluetooth.HandleRequestDevicePromptParameters , ) bluetooth.HandleRequestDevicePromptParameters = { context : text, prompt : bluetooth.RequestDevicePrompt , ( bluetooth.HandleRequestDevicePromptAcceptParameters // bluetooth.HandleRequestDevicePromptCancelParameters ) } bluetooth.HandleRequestDevicePromptAcceptParameters = ( accept : true, device : bluetooth.RequestDevice , ) bluetooth.HandleRequestDevicePromptCancelParameters = ( accept : false, )
-
令 contextId 为 params[
"context"]。 -
令 promptId 为 params[
"prompt"]。 -
令 accept 为 command parameters 的
accept字段之值。 -
如果 accept 为 true:
-
否则:
-
取消 prompt。
-
-
返回携带数据
null的成功。
{ "method" : "bluetooth.handleRequestDevicePrompt" , "params" : { "context" : "cxt-d03fdd81" , "prompt" : "pmt-e0a234b" , "accept" : true , "device" : "dvc-9b3b872" } }
12.2.3.2. bluetooth.simulateAdapter 命令
bluetooth.SimulateAdapter = ( method : "bluetooth.simulateAdapter" , params : bluetooth.SimulateAdapterParameters , ) bluetooth.SimulateAdapterParameters = { context : text, ? leSupported : bool, state : "absent" / "powered-off" / "powered-on" }
-
令 contextId 为 params[
"context"]。 -
如果 navigable 不是顶层可遍历对象,则返回错误,其错误码为invalid argument。
-
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
如果 simulatedBluetoothAdapter 为空,执行以下步骤:
-
如果 params[
"leSupported"]不存在,则将 params["leSupported"] 设为true。 -
令 simulatedBluetoothAdapter 为新的模拟 Bluetooth 适配器。
-
将 simulatedBluetoothAdapter 的LE 支持状态设为 params[
"leSupported"]。 -
将 simulatedBluetoothAdapter 的适配器状态设为 params[
"state"]。 -
将 navigable 的模拟 Bluetooth 适配器设为 simulatedBluetoothAdapter。
-
返回携带数据
null的成功。
-
-
如果 simulatedBluetoothAdapter 不为空,执行以下步骤:
{ "method" : "bluetooth.simulateAdapter" , "params" : { "context" : "cxt-d03fdd81" , "leSupported" : true , "state" : "powered-on" , } }
{ "method" : "bluetooth.simulateAdapter" , "params" : { "context" : "cxt-d03fdd81" , "state" : "powered-off" , } }
12.2.3.3. bluetooth.disableSimulation 命令
bluetooth.DisableSimulation = ( method : "bluetooth.disableSimulation" , params : bluetooth.DisableSimulationParameters , ) bluetooth.DisableSimulationParameters = { context : text}
-
令 contextId 为 params[
"context"]。 -
如果 navigable 不是顶层可遍历对象,则返回错误,其错误码为invalid argument。
-
将 navigable 的模拟 Bluetooth 适配器设为空。
-
返回携带数据
null的成功。
{ "method" : "bluetooth.disableSimulation" , "params" : { "context" : "cxt-d03fdd81" } }
12.2.3.4. bluetooth.simulatePreconnectedPeripheral 命令
bluetooth.SimulatePreconnectedPeripheral = ( method : "bluetooth.simulatePreconnectedPeripheral" , params : bluetooth.SimulatePreconnectedPeripheralParameters , ) bluetooth.SimulatePreconnectedPeripheralParameters = { context : text, address : text, name : text, manufacturerData : [ * bluetooth.BluetoothManufacturerData ], knownServiceUuids : [ * bluetooth.BluetoothUuid ] }
-
令 contextId 为 params["context"]。
-
如果 navigable 不是顶层可遍历对象,则返回错误,其错误码为invalid argument。
-
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
如果 simulatedBluetoothAdapter 为空,则返回错误,其错误码为invalid argument。
-
令 deviceAddress 为 params[
"address"]。 -
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
如果 deviceMapping[deviceAddress]存在,则返回错误,其错误码为invalid argument。
-
令 simulatedBluetoothDevice 为新的模拟 Bluetooth 设备。
-
将 simulatedBluetoothDevice 的名称设为 params[
"name"]。 -
将 simulatedBluetoothDevice 的地址设为 params[
"address"]。 -
将 simulatedBluetoothDevice 的制造商特定数据设为对 params[
"manufacturerData"] 执行宽松 base64 解码(forgiving-base64 decode)的输出。 -
将 simulatedBluetoothDevice 的服务 UUID设为 params[
"knownServiceUuids"]。 -
将 deviceMapping[deviceAddress] 设为 simulatedBluetoothDevice。
-
返回携带数据
null的成功。
{ "method" : "bluetooth.simulatePreconnectedPeripheral" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "name" : "Some Device" , "manufacturerData" : [ { key: 17 , data : "AP8BAX8=" } ], "knownServiceUuids" : [ "12345678-1234-5678-9abc-def123456789" , ], } }
12.2.3.5. bluetooth.simulateAdvertisement 命令
bluetooth.SimulateAdvertisement = ( method : "bluetooth.simulateAdvertisement" , params : bluetooth.SimulateAdvertisementParameters , ) bluetooth.SimulateAdvertisementParameters = { context : text, scanEntry : bluetooth.SimulateAdvertisementScanEntryParameters } bluetooth.SimulateAdvertisementScanEntryParameters = { deviceAddress : text, rssi : number, scanRecord : bluetooth.ScanRecord }
-
令 contextId 为 params[
"context"]。 -
如果 topLevelNavigable 不是顶层可遍历对象,则返回错误,其错误码为invalid argument。
-
令 scanEntry 为 params[
"scanEntry"]。 -
令 deviceAddress 为 scanEntry[
"deviceAddress"]。 -
令 simulatedBluetoothAdapter 为 topLevelNavigable 的模拟 Bluetooth 适配器。
-
如果 simulatedBluetoothAdapter 为空,则返回错误,其错误码为invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
如果 deviceMapping[deviceAddress]存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。否则,令 simulatedDevice 为带有 deviceAddress 的新的模拟 Bluetooth 设备,并将 deviceMapping[deviceAddress] 设为 simulatedDevice。
-
如果 topLevelNavigable 目前正在执行扫描设备(scan for devices)算法, 则将 simulatedDevice 插入该算法中的 simulatedBluetoothDevices 变量。
从另一个算法向变量中插入数据的规范性定义尚不明确。 扫描设备算法需要定义异步设备发现,以匹配实现行为。
-
令 navigables 为 topLevelNavigable 的包含式后代可导航对象集合, 基于其活动文档。
-
对 navigables 中的每个 navigable:
-
令 document 为 navigable 的活动文档。
-
在 document 的相关设置对象的负责事件循环上排队一个任务以执行以下子步骤:
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的关联 Bluetooth内, 获取表示该BluetoothDevicesimulatedDevice 的结果。 -
如果 simulatedDeviceInstance.
[[watchAdvertisementsState]]为not-watching,则中止这些子步骤。 -
为由 scanEntry[
"scanRecord"] 表示的广播事件,触发一个advertisementreceived事件,目标为 simulatedDeviceInstance。
-
-
-
返回携带数据
null的成功。
{ "method" : "bluetooth.simulateAdvertisement" , "params" : { "context" : "cxt-d03fdd81" , "scanEntry" : { "deviceAddress" : "08:08:08:08:08:08" , "rssi" : -10 , "scanRecord" : { "name" : "Heart Rate" , "uuids" : [ "0000180d-0000-1000-8000-00805f9b34fb" ], "manufacturerData" : [ { key: 17 , data : "AP8BAX8=" } ], "appearance" : 1 , "txPower" : 1 } } } }
12.2.3.6. bluetooth.simulateGattConnectionResponse 命令
bluetooth.SimulateGattConnectionResponse = ( method : "bluetooth.simulateGattConnectionResponse" , params : bluetooth.SimulateGattConnectionResponseParameters , ) bluetooth.SimulateGattConnectionResponseParameters = { context : text, address : text, code : uint}
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
如果 simulatedBluetoothAdapter 为空,则返回错误,其错误码为invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
如果 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress]; 否则,返回错误,其错误码为invalid argument。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的关联 Bluetooth内, 获取表示该BluetoothDevicesimulatedDevice 的结果。 -
如果 simulatedDeviceInstance.
[[gatt]].[[automatedGATTConnectionResponse]]为"expected", 则将 simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]设为 params["code"]。 -
否则,返回错误,其错误码为invalid element state。
0x00):
{ "method" : "bluetooth.simulateGattConnectionResponse" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "code" : 0 } }
12.2.3.7. bluetooth.simulateGattDisconnection 命令
bluetooth.SimulateGattDisconnection = ( method : "bluetooth.simulateGattDisconnection" , params : bluetooth.SimulateGattDisconnectionParameters , ) bluetooth.SimulateGattDisconnectionParameters = { context : text, address : text, }
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的 模拟 Bluetooth 适配器。
-
若 simulatedBluetoothAdapter 为空,返回错误,其错误码为 invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的 模拟 Bluetooth 设备映射。
-
若 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress];否则,返回错误,其错误码为 invalid argument。
-
令 simulatedDeviceInstance 为在 navigable 的 活动窗口 的 关联
Navigator的 关联 Bluetooth 内,获取表示 simulatedDevice 的BluetoothDevice的结果。 -
若 simulatedDeviceInstance.
[[gatt]].[[automatedGATTConnectionResponse]]为"expected",则将 simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]设为0x15。根据 错误码列表(List of Error Codes),0x15表示"Remote Device Terminated Connection due to Power Off"。这模拟了设备因断电而无法响应 GATT 连接尝试的场景。 -
否则,清理已断开连接的设备 simulatedDeviceInstance。
{ "method" : "bluetooth.simulateGattDisconnection" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , } }
12.2.3.8. bluetooth.simulateService 命令
bluetooth.SimulateService = ( method : "bluetooth.simulateService" , params : bluetooth.SimulateServiceParameters , ) bluetooth.SimulateServiceParameters = { context : text, address : text, uuid : bluetooth.BluetoothUuid , type : "add" / "remove" , }
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的 模拟 Bluetooth 适配器。
-
若 simulatedBluetoothAdapter 为空,返回错误,其错误码为 invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的 模拟 Bluetooth 设备映射。
-
若 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 simulatedDeviceInstance 为在 navigable 的 活动窗口 的 关联
Navigator的 关联 Bluetooth 内,获取表示 simulatedDevice 的BluetoothDevice的结果。 -
令 serviceMapping 为 simulatedDevice 的 模拟 GATT 服务映射。
-
令 uuid 为 params[
"uuid"]。 -
若 params[
"type"] 为"add":-
若 serviceMapping[uuid]存在,返回错误,其错误码为 invalid element state。
-
令 simulatedGattService 为新的 模拟 GATT 服务。
-
将 simulatedGattService 的 UUID 设为 uuid。
-
将 serviceMapping[uuid] 设为 simulatedGattService。
-
创建表示 simulatedGattService 的
BluetoothRemoteGATTService,并在 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]中添加从 simulatedGattService 到所得Promise的映射。 -
返回携带数据
null的成功。
-
-
若 params[
"type"] 为"remove":-
若 serviceMapping[uuid]存在,令 simulatedGattService 为 serviceMapping[uuid]。
-
否则,返回错误,其错误码为 invalid element state。
-
从 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]]中移除 simulatedGattService。 -
从 serviceMapping 中移除 uuid。
-
返回携带数据
null的成功。
-
-
返回错误,其错误码为 invalid argument。
{ "method" : "bluetooth.simulateService" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "uuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "type" : "add" } }
{ "method" : "bluetooth.simulateService" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "uuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "type" : "remove" } }
12.2.3.9. bluetooth.simulateCharacteristic 命令
bluetooth.SimulateCharacteristic = ( method : "bluetooth.simulateCharacteristic" , params : bluetooth.SimulateCharacteristicParameters , ) bluetooth.SimulateCharacteristicParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , ? characteristicProperties : bluetooth.CharacteristicProperties , type : "add" / "remove" }
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
若 simulatedBluetoothAdapter 为空,返回错误,其错误码为 invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
若 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth 内,获取表示该BluetoothDevicesimulatedDevice 的结果。 -
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
若 serviceMapping[serviceUuid]存在,令 simulatedService 为 serviceMapping[serviceUuid]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征值映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
若 params[
"type"] 为"add":-
若 characteristicMapping[characteristicUuid]存在,返回错误,其 错误码为 invalid element state。
-
若 params[
"characteristicProperties"]不存在,返回错误,其错误码为 invalid argument。 -
令 simulatedGattCharacteristicProperties 为新的模拟 GATT 特征值属性,并执行以下步骤:
-
令 properties 为 params[
"characteristicProperties"]。 -
若 properties[
"broadcast"]存在,且 properties["broadcast"] 为true,则设置 simulatedGattCharacteristicProperties 的Broadcast位。 -
若 properties[
"read"]存在,且 properties["read"] 为true,则设置 simulatedGattCharacteristicProperties 的Read位。 -
若 properties[
"writeWithoutResponse"]存在,且 properties["writeWithoutResponse"] 为true,则设置 simulatedGattCharacteristicProperties 的Write Without Response位。 -
若 properties[
"write"]存在,且 properties["write"] 为true,则设置 simulatedGattCharacteristicProperties 的Write位。 -
若 properties[
"notify"]存在,且 properties["notify"] 为true,则设置 simulatedGattCharacteristicProperties 的Notify位。 -
若 properties[
"indicate"]存在,且 properties["indicate"] 为true,则设置 simulatedGattCharacteristicProperties 的Indicate位。 -
若 properties[
"authenticatedSignedWrites"]存在,且 properties["authenticatedSignedWrites"] 为true,则设置 simulatedGattCharacteristicProperties 的Authenticated Signed Writes位。 -
若 properties[
"extendedProperties"]存在,且 properties["extendedProperties"] 为true,则设置 simulatedGattCharacteristicProperties 的Extended Properties位。
-
-
令 simulatedGattCharacteristic 为新的模拟 GATT 特征值。
-
将 simulatedGattCharacteristic 的UUID 设为 characteristicUuid。
-
将 simulatedGattCharacteristic 的特征值属性设为 simulatedGattCharacteristicProperties。
-
将 characteristicMapping[characteristicUuid] 设为 simulatedGattCharacteristic。
-
创建表示 simulatedGattCharacteristic 的
BluetoothRemoteGATTCharacteristic, 并在 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]中添加从 simulatedGattCharacteristic 到所得Promise的映射。 -
返回携带数据
null的成功。
-
-
若 params[
"type"] 为"remove":-
若 params[
"characteristicProperties"]存在,返回错误,其错误码为 invalid argument。 -
若 characteristicMapping[characteristicUuid]存在,令 simulatedGattCharacteristic 为 characteristicMapping[characteristicUuid]。
-
否则,返回错误,其错误码为 invalid element state。
-
从 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]]中移除 simulatedGattCharacteristic。 -
从 characteristicMapping 中移除 characteristicUuid。
-
返回携带数据
null的成功。
-
-
返回错误,其错误码为 invalid argument。
{ "method" : "bluetooth.simulateCharacteristic" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "characteristicProperties" : { "read" : true , "write" : true , "notify" : true }, "type" : "add" } }
{ "method" : "bluetooth.simulateCharacteristic" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "type" : "remove" } }
12.2.3.10. bluetooth.simulateCharacteristicResponse 命令
bluetooth.SimulateCharacteristicResponse = ( method : "bluetooth.simulateCharacteristicResponse" , params : bluetooth.SimulateCharacteristicResponseParameters , ) bluetooth.SimulateCharacteristicResponseParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , type : "read" / "write" / "subscribe-to-notifications" / "unsubscribe-from-notifications" , code : uint, ? data : [ * uint] }
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
若 simulatedBluetoothAdapter 为空,返回错误,其错误码为 invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
若 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress];否则,返回错误,其错误码为 invalid argument。
-
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
若 serviceMapping[serviceUuid]存在,令 simulatedService 为 serviceMapping[serviceUuid]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征值映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
若 characteristicMapping[characteristicUuid]存在,令 simulatedGattCharacteristic 为 characteristicMapping[characteristicUuid]。
-
否则,返回错误,其错误码为 invalid element state。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth 内,获取表示该BluetoothDevicesimulatedDevice 的结果。 -
令 promise 为 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]][simulatedGattCharacteristic]。 -
Upon fulfillment of promise with characteristic,执行以下步骤:
-
若 params[
"type"] 为read,执行以下步骤:-
若 characteristic.
[[automatedCharacteristicReadResponse]]为expected, 则将 characteristic.[[automatedCharacteristicReadResponse]]设为 params["code"],并将 characteristic.[[automatedCharacteristicReadResponseData]]设为所持字节的副本, 这些字节来自 params["data"]。 -
否则,返回错误,其错误码为 invalid element state。
-
-
若 params[
"type"] 为write,执行以下步骤:-
若 characteristic.
[[automatedCharacteristicWriteResponse]]为expected, 则将 characteristic.[[automatedCharacteristicWriteResponse]]设为 params["code"]。 -
否则,返回错误,其错误码为 invalid element state。
-
-
若 params[
"type"] 为subscribe-to-notifications,执行以下步骤:-
若 characteristic.
[[automatedCharacteristicSubscribeToNotificationsResponse]]为expected, 则将 characteristic.[[automatedCharacteristicSubscribeToNotificationsResponse]]设为 params["code"]。 -
否则,返回错误,其错误码为 invalid element state。
-
-
若 params[
"type"] 为unsubscribe-from-notifications,执行以下步骤:-
若 characteristic.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]为expected, 则将 characteristic.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]设为 params["code"]。 -
否则,返回错误,其错误码为 invalid element state。
-
-
否则,返回错误,其 错误码为 invalid argument。
-
0x00),并携带数据:
{ "method" : "bluetooth.simulateCharacteristicResponse" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "type" : "read" , "code" : 0 , "data" : [ 1 , 2 ] } }
12.2.3.11. bluetooth.simulateDescriptor 命令
bluetooth.SimulateDescriptor = ( method : "bluetooth.simulateDescriptor" , params : bluetooth.SimulateDescriptorParameters , ) bluetooth.SimulateDescriptorParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , descriptorUuid : bluetooth.BluetoothUuid , type : "add" / "remove" }
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
若 simulatedBluetoothAdapter 为空,返回错误,其错误码为 invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
若 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth 内,获取表示该BluetoothDevicesimulatedDevice 的结果。 -
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
若 serviceMapping[serviceUuid]存在,令 simulatedService 为 serviceMapping[serviceUuid]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征值映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
若 characteristicMapping[characteristicUuid]存在,令 simulatedCharacteristic 为 characteristicMapping[characteristicUuid]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 descriptorMapping 为 simulatedCharacteristic 的模拟 GATT 描述符映射。
-
令 descriptorUuid 为 params[
"descriptorUuid"]。 -
若 params[
"type"] 为"add":-
若 descriptorMapping[descriptorUuid]存在,返回错误,其 错误码为 invalid element state。
-
令 simulatedGattDescriptor 为新的模拟 GATT 描述符。
-
将 simulatedGattDescriptor 的UUID 设为 descriptorUuid。
-
将 descriptorMapping[descriptorUuid] 设为 simulatedGattDescriptor。
-
创建表示 simulatedGattDescriptor 的
BluetoothRemoteGATTDescriptor, 并在 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]中添加从 simulatedGattDescriptor 到所得Promise的映射。 -
返回携带数据
null的成功。
-
-
若 params[
"type"] 为"remove":-
若 descriptorMapping[descriptorUuid]存在,令 simulatedGattDescriptor 为 descriptorMapping[descriptorUuid]。
-
否则,返回错误,其错误码为 invalid element state。
-
从 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]]中移除 simulatedGattDescriptor。 -
从 descriptorMapping 中移除 descriptorUuid。
-
返回携带数据
null的成功。
-
-
返回错误,其错误码为 invalid argument。
{ "method" : "bluetooth.simulateDescriptor" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "descriptorUuid" : "00002901-0000-1000-8000-00805f9b34fb" , "type" : "add" } }
{ "method" : "bluetooth.simulateDescriptor" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "descriptorUuid" : "00002901-0000-1000-8000-00805f9b34fb" , "type" : "remove" } }
12.2.3.12. bluetooth.simulateDescriptorResponse 命令
bluetooth.SimulateDescriptorResponse = ( method : "bluetooth.simulateDescriptorResponse" , params : bluetooth.SimulateDescriptorResponseParameters , ) bluetooth.SimulateDescriptorResponseParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , descriptorUuid : bluetooth.BluetoothUuid , type : "read" / "write" , code : uint, ? data : [ * uint] }
-
令 contextId 为 params[
"context"]。 -
令 deviceAddress 为 params[
"address"]。 -
令 simulatedBluetoothAdapter 为 navigable 的模拟 Bluetooth 适配器。
-
若 simulatedBluetoothAdapter 为空,返回错误,其错误码为 invalid argument。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟 Bluetooth 设备映射。
-
若 deviceMapping[deviceAddress]存在,令 simulatedDevice 为 deviceMapping[deviceAddress];否则,返回错误,其错误码为 invalid argument。
-
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
若 serviceMapping[serviceUuid]存在,令 simulatedService 为 serviceMapping[serviceUuid]。
-
否则,返回错误,其错误码为 invalid argument。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征值映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
若 characteristicMapping[characteristicUuid]存在,令 simulatedCharacteristic 为 characteristicMapping[characteristicUuid]。
-
否则,返回错误,其错误码为 invalid element state。
-
令 descriptorMapping 为 simulatedCharacteristic 的模拟 GATT 描述符映射。
-
令 descriptorUuid 为 params[
"descriptorUuid"]。 -
若 descriptorMapping[descriptorUuid]存在,令 simulatedDescriptor 为 descriptorMapping[descriptorUuid]。
-
否则,返回错误,其错误码为 invalid element state。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth 内,获取表示该BluetoothDevicesimulatedDevice 的结果。 -
令 promise 为 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]][simulatedDescriptor]。 -
Upon fulfillment of promise with descriptor,执行以下步骤:
-
若 params[
"type"] 为read,执行以下步骤:-
若 descriptor.
[[automatedDescriptorReadResponse]]为expected, 则将 descriptor.[[automatedDescriptorReadResponse]]设为 params["code"],并将 descriptor.[[automatedDescriptorReadResponseData]]设为所持字节的副本, 这些字节来自 params["data"]。 -
否则,返回错误,其错误码为 invalid element state。
-
-
若 params[
"type"] 为write,执行以下步骤:-
若 characteristic.
[[automatedDescriptorWriteResponse]]为expected, 则将 characteristic.[[automatedDescriptorWriteResponse]]设为 params["code"]。 -
否则,返回错误,其错误码为 invalid element state。
-
-
否则,返回错误,其 错误码为 invalid argument。
-
0x00),并携带数据:
{ "method" : "bluetooth.simulateDescriptorResponse" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "descriptorUuid" : "00002901-0000-1000-8000-00805f9b34fb" , "type" : "read" , "code" : 0 , "data" : [ 1 , 2 ] } }
12.2.4. 事件
BluetoothEvent = ( bluetooth.RequestDevicePromptUpdated // bluetooth.GattConnectionAttempted )
12.2.4.1. bluetooth.requestDevicePromptUpdated 事件
bluetooth.RequestDevicePromptUpdated = ( method : "bluetooth.requestDevicePromptUpdated" , params : bluetooth.RequestDevicePromptUpdatedParameters ) bluetooth.RequestDevicePromptUpdatedParameters = { context : text, prompt : bluetooth.RequestDevicePrompt , devices : [ * bluetooth.RequestDeviceInfo ], }
-
令 navigableId 为 navigable 的navigable id。
-
令 prompt 为设备提示(promptId, devices)。
-
令 serialized devices 为以 prompt 作为输入序列化提示中的设备的结果。
-
将navigable 到设备提示的映射[navigableId] 设为 prompt。
-
令 params 为一个与
bluetooth.RequestDevicePromptUpdatedParameters产生式匹配的映射,其中context字段设为 navigableId,prompt字段设为 promptId,devices字段设为 serialized devices。 -
令 body 为一个与
bluetooth.RequestDevicePromptUpdated产生式匹配的映射,其中params字段设为 params。 -
令 relatedNavigables 为包含 navigable 的集合。
-
对于给定 "
bluetooth.requestDevicePromptUpdated" 与 relatedNavigables 的已启用该事件的会话集合中的每个 session:-
触发事件(Emit an event),携带 session 与 body。
-
12.2.4.2. bluetooth.gattConnectionAttempted 事件
bluetooth.GattConnectionAttempted = ( method : "bluetooth.gattConnectionAttempted" , params : bluetooth.GattConnectionAttemptedParameters ) bluetooth.GattConnectionAttemptedParameters = { context : text, address : text}
BluetoothDevice
device 的情况下,触发一个 gatt 连接尝试事件:
-
令 navigableId 为 navigable 的navigable id。
-
令 params 为一个与
bluetooth.GattConnectionAttemptedParameters产生式匹配的映射,其中context字段设为 navigableId,address字段设为 device.[[representedDevice]]的地址。 -
令 body 为一个与
bluetooth.GattConnectionAttempted产生式匹配的映射,其中params字段设为 params。 -
令 relatedNavigables 为包含 navigable 的集合。
-
对于给定 "
bluetooth.gattEventGenerated" 与 relatedNavigables 的已启用该事件的会话集合中的每个 session:-
触发事件(Emit an event),携带 session 与 body。
-
12.2.4.3. bluetooth.characteristicEventGenerated 事件
bluetooth.CharacteristicEventGenerated = ( method : "bluetooth.characteristicEventGenerated" , params : bluetooth.CharacteristicEventGeneratedParameters ) bluetooth.CharacteristicEventGeneratedParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , type : "read" / "write-with-response" / "write-without-response" / "subscribe-to-notifications" / "unsubscribe-from-notifications" , ? data : [ * uint] }
要在给定一个navigable navigable、一个 BluetoothDevice
device、一个模拟 GATT 特征值 characteristic、字符串
type,以及可选的字节序列
bytes 的情况下,触发一个模拟的特征值事件:
-
令 navigableId 为 navigable 的navigable id。
-
令 params 为一个与
bluetooth.CharacteristicEventGeneratedParameters产生式匹配的映射,并执行以下步骤:-
设 params[
"context"] 为 navigableId。 -
设 params[
"address"] 为 device.[[representedDevice]]的地址。 -
令 service 为包含 characteristic 的模拟 GATT 服务。
-
设 params[
"serviceUuid"] 为 service 的UUID。 -
设 params[
"characteristicUuid"] 为 characteristic 的UUID。 -
设 params[
"type"] 为 type。 -
如果 type 为
write,执行以下步骤:-
令 data 为空列表。
-
对于 bytes 中的每个 byte:
-
将 byte 的值追加到 data。
-
-
设 params[
"data"] 为 data。
-
-
-
令 body 为一个与
bluetooth.CharacteristicEventGenerated产生式匹配的映射,其中params字段设为 params。 -
令 relatedNavigables 为包含 navigable 的集合。
-
对于给定 "
bluetooth.characteristicEventGenerated" 与 relatedNavigables 的已启用该事件的会话集合中的每个 session:-
触发事件(Emit an event),携带 session 与 body。
-
12.2.4.4. bluetooth.descriptorEventGenerated 事件
bluetooth.DescriptorEventGenerated = ( method : "bluetooth.descriptorEventGenerated" , params : bluetooth.DescriptorEventGeneratedParameters ) bluetooth.DescriptorEventGeneratedParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , descriptorUuid : bluetooth.BluetoothUuid , type : "read" / "write" , ? data : [ * uint] }
要在给定一个navigable navigable、一个 BluetoothDevice
device、一个模拟 GATT 描述符 descriptor、字符串
type,以及可选的字节序列
bytes 的情况下,触发一个模拟的描述符事件:
-
令 navigableId 为 navigable 的navigable id。
-
令 params 为一个与
bluetooth.DescriptorEventGeneratedParameters产生式匹配的映射,并执行以下步骤:-
设 params[
"context"] 为 navigableId。 -
设 params[
"address"] 为 device.[[representedDevice]]的地址。 -
令 characteristic 为包含 descriptor 的模拟 GATT 特征值。
-
令 service 为包含 characteristic 的模拟 GATT 服务。
-
设 params[
"serviceUuid"] 为 service 的UUID。 -
设 params[
"characteristicUuid"] 为 characteristic 的UUID。 -
设 params[
"descriptorUuid"] 为 descriptor 的UUID。 -
设 params[
"type"] 为 type。 -
如果 type 为
write,执行以下步骤:-
令 data 为空列表。
-
对于 bytes 中的每个 byte:
-
将 byte 的值追加到 data。
-
-
设 params[
"data"] 为 data。
-
-
-
令 body 为一个与
bluetooth.DescriptorEventGenerated产生式匹配的映射,其中params字段设为 params。 -
令 relatedNavigables 为包含 navigable 的集合。
-
对于给定 "
bluetooth.descriptorEventGenerated" 与 relatedNavigables 的已启用该事件的会话集合中的每个 session:-
触发事件(Emit an event),携带 session 与 body。
-
13. 术语与约定
本规范使用了一些约定以及来自其他规范的若干术语。本节列出了这些内容并链接到它们的主要定义。
当本规范中的算法使用在本规范或其他规范中定义的名称时,该名称必须解析为其初始值,忽略在当前执行环境中对该名称所做的任何更改。例如,当
requestDevice()
算法要求调用
时,必须应用 [ECMAScript] 中定义的
Array.prototype.map.call(filter.services,
BluetoothUUID.getService)Array.prototype.map
算法,以 filter.services 作为其 this 参数,并以 § 7.1
标准化 UUID 中为
BluetoothUUID.getService
定义的算法作为其 callbackfn 参数,而不论对
window、Array、Array.prototype、Array.prototype.map、
Function、Function.prototype、BluetoothUUID、BluetoothUUID.getService
或其他对象进行了怎样的修改。
本规范使用一种只读类型,其类似于 WebIDL 的
FrozenArray。
-
只读 ArrayBuffer 具有
ArrayBuffer的取值与接口, 但尝试写入其内容或传输它,与尝试写入FrozenArray的内容具有相同效果。这同样适用于包裹该ArrayBuffer的TypedArray与DataView。
- [BLUETOOTH42]
-
-
架构与术语概览
-
概述
- Bluetooth 低功耗(BLE)操作概览 (定义了 广播事件)
-
通信拓扑与操作
-
运行过程与模式
-
BR/EDR 过程
-
Inquiry(发现)过程
- 扩展 Inquiry 响应(Extended Inquiry Response)
-
Inquiry(发现)过程
-
BR/EDR 过程
-
运行过程与模式
-
概述
-
核心系统包 [BR/EDR 控制器卷]
-
错误码
-
错误码概览
- 错误码列表
-
错误码概览
-
主机控制器接口(HCI)功能规范
-
HCI 命令与事件
-
信息参数
- 读取 BD_ADDR 命令
-
状态参数
- 读取 RSSI 命令
-
信息参数
-
HCI 命令与事件
-
错误码
-
核心系统包 [主机卷]
-
服务发现协议(SDP)规范
-
概览
-
服务搜索
- UUID (定义了 UUID 别名以及由 UUID 别名计算 所表示的 128 位 UUID 的算法)
-
服务搜索
-
概览
-
通用接入配置文件(GAP)
-
配置文件概览
-
配置文件角色
-
在 LE 物理传输上的角色
- 广播者(Broadcaster)角色
- 观察者(Observer)角色
- 外设(Peripheral)角色
- 中心(Central)角色
-
在 LE 物理传输上的角色
-
配置文件角色
-
用户界面方面
-
Bluetooth 参数的表示
- Bluetooth 设备名称(用户可读名称)
-
Bluetooth 参数的表示
-
空闲模式过程 — BR/EDR 物理传输
- 设备发现过程
- BR/EDR 绑定过程
-
运行模式与过程 — LE 物理传输
-
广播模式与观察过程
- 观察过程
-
发现模式与过程
- 一般发现过程
- 名称发现过程
- 连接模式与过程
-
绑定模式与过程
- LE 绑定过程
-
广播模式与观察过程
-
安全方面 — LE 物理传输
- 隐私特性
-
随机设备地址
- 静态地址
-
私有地址
- 可解析私有地址解析过程
- 广播数据(Advertising Data)与扫描响应数据格式 (定义了 AD 结构)
-
Bluetooth 设备需求
-
Bluetooth 设备地址(定义了 BD_ADDR)
-
Bluetooth 设备地址类型
- 公共 Bluetooth 地址
-
Bluetooth 设备地址类型
-
Bluetooth 设备地址(定义了 BD_ADDR)
- 定义 (定义了 绑定(bond))
-
配置文件概览
-
属性协议(ATT)
-
协议需求
-
基本概念
- 属性类型
- 属性句柄
- 长属性值
-
属性协议 PDU
-
错误处理
- 错误响应(Error Response)
-
错误处理
-
基本概念
-
协议需求
-
通用属性配置文件(GATT)
-
配置文件概览
- 配置与角色 (定义了 GATT 客户端与 GATT 服务端)
- 配置文件基础, 定义了 ATT 承载(Bearer)
-
属性协议
- 属性缓存
-
GATT 配置文件层级
- 服务(Service)
- 包含的服务(Included Service)
- 特征值(Characteristic)
-
服务互操作性需求
- 服务定义
-
特征值定义
-
特征值声明
- 特征值属性
-
特征值 描述符(Descriptor) 声明
- 特征值扩展属性
- 客户端特征值配置
-
特征值声明
-
GATT 功能需求 — 定义了
GATT 过程。
-
服务器配置
- 交换 MTU(Exchange MTU)
-
主服务发现
- 发现所有主服务
- 根据服务 UUID 发现主服务
-
关系发现
- 查找包含的服务
-
特征值发现
- 发现服务的所有特征值
- 按 UUID 发现特征值
-
特征值描述符发现
- 发现所有特征值描述符
- 特征值读取
-
特征值写入
- 无响应写入
- 写入特征值
- 特征值通知
- 特征值指示
-
特征值描述符
- 读取特征值描述符
- 读取长特征值描述符
- 写入特征值描述符
- 写入长特征值描述符
- 过程超时
-
服务器配置
-
GAP 互操作性需求
-
BR/EDR GAP 互操作性需求
- 建立连接
-
LE GAP 互操作性需求
- 建立连接
-
BR/EDR GAP 互操作性需求
-
已定义的通用属性配置文件服务
- Service Changed
-
配置文件概览
-
安全管理器规范
-
安全管理器
-
Bluetooth 低功耗中的安全
- 密钥与取值定义, 定义了 身份解析密钥 (IRK)
-
Bluetooth 低功耗中的安全
-
安全管理器
-
服务发现协议(SDP)规范
-
核心系统包 [低功耗控制器卷]
-
链路层规范
-
概述
-
设备地址
- 公共设备地址
-
随机设备地址
- 静态设备地址
-
设备地址
-
空中接口协议
-
非连接状态
-
扫描状态
- 被动扫描
-
扫描状态
-
非连接状态
-
概述
-
链路层规范
-
架构与术语概览
- [BLUETOOTH-SUPPLEMENT6]
-
-
数据类型规范
-
数据类型定义与格式
- 服务 UUID 数据类型
- 本地名称数据类型
- 标志数据类型 (定义了 可发现模式 标志)
- 厂商特定数据
- 发射功率级别(TX Power Level)
- 服务数据
- 外观(Appearance)
-
数据类型定义与格式
-
数据类型规范