1. 引言
本节为非规范性内容。
蓝牙是用于 设备之间短距离无线通信的标准。蓝牙“经典”模式(BR/EDR) 定义了一组二进制协议,并支持最高约 24Mbps 的速度。 蓝牙 4.0 引入了一种称为“Bluetooth Smart”的新“低功耗”模式, 即 BLE,也简称为 LE, 其速度限制在约 1Mbps,但允许设备在大部分时间关闭其发射器。 BLE 的大部分功能通过由通用属性 配置文件(GATT)提供的键/值 对实现。
BLE 定义了设备可承担的多种角色。广播者和 观察者角色分别用于仅发射和 仅接收的应用。 以外围设备角色运行的设备可以接收 连接,而以中心设备角色运行的设备可以连接到 外围设备。
以外围设备或中心设备角色运行的设备均可托管 一个GATT 服务器,该服务器公开由 服务、 特征和描述符构成的层次结构。有关 此层次结构的更多详细信息,请参见§ 6.1 GATT 信息模型。尽管 GATT 协议被设计为支持 BLE 传输,但它也可以在 BR/EDR 传输上运行。
本规范的第一个版本允许网页在以 中心设备角色运行的 UA 上,通过 BR/EDR 或 LE 连接来连接GATT 服务器。虽然本规范引用了[BLUETOOTH42] 规范, 但其目标也包括支持仅实现 蓝牙 4.0 或 4.1 的设备之间的通信。
1.1. 示例
let chosenHeartRateService= null ; navigator. bluetooth. requestDevice({ filters: [{ services: [ 'heart_rate' ], }] }). then( device=> device. gatt. connect() ) . then( server=> server. getPrimaryService( 'heart_rate' )) . then( service=> { chosenHeartRateService= service; return Promise. all([ service. getCharacteristic( 'body_sensor_location' ) . then( handleBodySensorLocationCharacteristic), service. getCharacteristic( 'heart_rate_measurement' ) . then( handleHeartRateMeasurementCharacteristic), ]); }); function handleBodySensorLocationCharacteristic( characteristic) { if ( characteristic=== null ) { console. log( "未知的传感器位置。" ); return Promise. resolve(); } return characteristic. readValue() . then( sensorLocationData=> { const sensorLocation= sensorLocationData. getUint8( 0 ); switch ( sensorLocation) { case 0 : return '其他' ; case 1 : return '胸部' ; case 2 : return '手腕' ; case 3 : return '手指' ; case 4 : return '手部' ; case 5 : return '耳垂' ; case 6 : return '足部' ; default : return '未知' ; } }). then( location=> console. log( location)); } function handleHeartRateMeasurementCharacteristic( characteristic) { return characteristic. startNotifications() . then( char => { characteristic. addEventListener( ' characteristicvaluechanged ' , onHeartRateChanged); }); } function onHeartRateChanged( event) { const characteristic= event. target; console. log( parseHeartRate( characteristic. value)); }
parseHeartRate() 将根据
heart_rate_measurement 文档
进行定义,以读取存储在 DataView
中的 BluetoothRemoteGATTCharacteristic
的
value
字段。
function parseHeartRate( data) { const flags= data. getUint8( 0 ); const rate16Bits= flags& 0x1 ; const result= {}; let index= 1 ; if ( rate16Bits) { result. heartRate= data. getUint16( index, /*小端序=*/ true ); index+= 2 ; } else { result. heartRate= data. getUint8( index); index+= 1 ; } const contactDetected= flags& 0x2 ; const contactSensorPresent= flags& 0x4 ; if ( contactSensorPresent) { result. contactDetected= !! contactDetected; } const energyPresent= flags& 0x8 ; if ( energyPresent) { result. energyExpended= data. getUint16( index, /*小端序=*/ true ); index+= 2 ; } const rrIntervalPresent= flags& 0x10 ; if ( rrIntervalPresent) { const rrIntervals= []; for (; index+ 1 < data. byteLength; index+= 2 ) { rrIntervals. push( data. getUint16( index, /*小端序=*/ true )); } result. rrIntervals= rrIntervals; } return result; }
onHeartRateChanged() 可能记录如下对象
{ heartRate: 70 , contactDetected: true , energyExpended: 750 , // 表示 750kJ。 rrIntervals: [ 890 , 870 ] // 表示 .87s 和 .85s。 }
如果心率传感器报告 energyExpended 字段,Web
应用可以通过向
heart_rate_control_point
特征写入数据,将其值重置为 0:
function resetEnergyExpended() { if ( ! chosenHeartRateService) { return Promise. reject( new Error ( '尚未选择心率传感器。' )); } return chosenHeartRateService. getCharacteristic( 'heart_rate_control_point' ) . then( controlPoint=> { const resetEnergyExpended= new Uint8Array([ 1 ]); return controlPoint. writeValue( resetEnergyExpended); }); }
2. 安全考虑
请参见§ 3 隐私考虑一节。[Issue #575]
3. 隐私考虑
3.1. 设备访问能力强大
当网站使用 requestDevice()
请求访问设备时,它会获得访问该调用中提到的所有 GATT 服务的能力。UA
必须在询问用户要信任哪些设备之前,告知用户这些服务会赋予网站哪些能力。
如果列表中的任何服务对 UA 而言是未知的,UA 必须假定这些服务会赋予网站对
设备的完全控制权,并告知用户此风险。UA 还必须允许用户
查看哪些网站可以访问哪些设备,并撤销这些配对。
UA 不得允许用户将整个设备类别与网站配对。 可以构造这样一种设备类别,其中每个单独的设备 都发送相同的蓝牙层标识信息。UA 无须 尝试检测这种伪造,并且可以允许用户将此 伪设备与网站配对。
为了帮助确保只有用户批准访问的实体才能真正获得 访问权限,本规范要求只有安全上下文才能访问 蓝牙设备。
3.2. 受信任的服务器可能提供恶意代码
本节为非规范性内容。
即使用户信任某个源,该源的服务器或开发者仍可能被 攻破,或者该源的网站可能容易受到 XSS 攻击。这两种情况 都可能导致用户授予恶意代码访问重要设备的权限。源 应定义内容安全策略([CSP3])以降低 XSS 攻击的风险,但这无法防范服务器或开发者被攻破的情况。
§ 4.1 Permission API 集成提供的在页面重新加载后检索已授权设备的能力,会使这种风险更加严重。攻击者 不必在网站被攻破期间诱使用户授予访问权限, 只要用户在网站被攻破期间访问该网站,攻击者就可以利用 先前已授权的设备。另一方面,当网站可以在页面重新加载之间保持 对设备的访问权限时,总体上就不必显示那么多 权限提示,从而使用户更有可能关注 他们实际看到的提示。
3.3. 针对设备的攻击
本节为非规范性内容。
来自网站的通信可能破坏某些设备的安全模型,这些设备 假定自己只会从远程设备受信任的操作系统接收消息。 人机接口设备就是一个典型例子,在这种情况下,允许 网站进行通信将使该网站能够记录按键。本 规范包含一个此类易受攻击的服务、 特征和描述符的 GATT 阻止列表,以防止网站利用 它们。
我们预计许多设备容易受到发送到其 无线电接口的意外数据的影响。过去,这些设备必须逐个利用,但此 API 使进行大规模攻击成为可能。本规范采用 多种方法来增加此类攻击的难度:
-
配对单个设备而不是设备类别,要求至少进行一次用户 操作后设备才能被利用。
-
将访问限制为GATT,而不是通用字节流访问, 可阻止恶意网站访问设备上的大多数解析器。
另一方面,GATT 的特征和描述符值 仍然是字节数组,而这些数组可以被设置为设备 未预期的长度和格式。鼓励 UA 在可能时验证这些值。
-
此 API 从不向网站暴露蓝牙寻址、数据签名或加密密钥 (键和值的定义)。这使得 网站更难预测将通过无线电发送的位,从而阻止包中包 注入攻击。遗憾的是,这仅适用于加密链路, 而并非所有 BLE 设备都必须支持加密链路。
-
与§ 11.1 权限策略的集成为 防止未经授权访问蓝牙功能提供了保护,它要求顶级文档 明确允许跨源 iframe 使用该 API 的方法。
UA 还可以采取进一步措施来保护用户:
-
Web 服务可以收集恶意网站和易受攻击设备的列表。 UA 可以拒绝恶意网站访问任何设备,也可以拒绝任何网站访问 易受攻击的设备。
3.4. 蓝牙设备标识符
本节为非规范性内容。
每个蓝牙 BR/EDR 设备都有一个称为 BD_ADDR 的唯一 48 位 MAC 地址。每个蓝牙 LE 设备至少具有 公共设备 地址和静态设备地址之一。公共设备地址 是一个 MAC 地址。静态设备地址可能会在每次 重启时重新生成。BR/EDR/LE 设备会对 BD_ADDR 和 公共设备 地址使用相同的值(在Read BD_ADDR 命令中规定)。
LE 设备还可能具有唯一的 128 位身份解析密钥, 该密钥会在绑定过程中发送给受信任的设备。为了避免泄露 持久标识符,LE 设备在扫描和广播时可以使用随机 的可解析或不可解析私有地址,而不是其静态或 公共地址。这些地址会定期重新生成(大约每 15 分钟一次),但已绑定的设备可以使用IRK 检查其存储的某个 IRK 是否与给定的可解析私有地址匹配,方法是使用可解析私有 地址解析过程。
每个蓝牙设备还有一个人类可读的蓝牙设备名称。 这些名称不保证唯一,但根据设备 类型的不同,它们很可能是唯一的。
3.4.1. 远程蓝牙设备的标识符
本节为非规范性内容。
如果网站能够检索任何持久设备 ID,则这些 ID 可与 对周围设备进行大规模编目的工作结合使用,以确定 用户的位置。设备 ID 还可用于识别将 两个不同网站与同一蓝牙设备配对的用户是同一用户。另一方面, 许多可用的 GATT 服务都可用于对 设备进行指纹识别,并且设备可以轻易公开自定义 GATT 服务,使此操作 更加容易。
本规范建议 UA 在用户无意让脚本知道它们是同一设备时, 对同一设备使用不同的设备 ID,从而使 网站更难以这种方式滥用设备地址。设备制造商仍然可以设计 帮助跟踪用户的设备,但这需要额外工作。
3.4.2. UA 的蓝牙地址
本节为非规范性内容。
在 BR/EDR 模式下,或者在未使用隐私 功能进行主动扫描的 LE 模式下,UA 会向附近的任何蓝牙无线电广播其持久 ID。 这使攻击者很容易在某个区域散布恶意设备并跟踪 UA。截至 2014-08,几乎没有平台记录其实现了隐私 功能,因此尽管本规范推荐使用该功能,但很少有 UA 可能会使用它。 本规范确实要求用户手势 才能让网站触发扫描,这在一定程度上降低了扫描频率,但 如果有更多平台公开隐私 功能,效果会更好。
3.5. 暴露蓝牙可用性
本节为非规范性内容。
navigator.bluetooth.
会暴露用户系统上是否有
蓝牙无线电可用,而不考虑其是否已开启。如果用户已配置
UA 阻止 Web Bluetooth,可用性也会受到影响。一些用户可能认为这是隐私信息,
尽管很难想象暴露它会造成什么损害。这些
信息也会略微增加 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
成员getAvailability()
会告知页面蓝牙是否
完全可用。通过软件禁用的适配器仍应视为
可用。可用性的变化,例如用户物理地
连接或断开适配器时,会通过
availabilitychanged
事件报告。
referringDevice
提供对用户从中
打开此页面的设备的访问(如果存在)。例如,Eddystone 信标
可能会广播一个 URL,UA 允许用户打开该 URL。表示该信标的
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 | <无> |
如果网站调用
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 | <无> |
| D3 | Device Third |
| D4 | Device Fourth |
| D5 | Unique Name |
下表显示,对于传递给
navigator.bluetooth.requestDevice({filters: filters})
的若干 filters 值,用户可以在哪些设备之间进行选择。
| filters | 设备 | 注释 |
|---|---|---|
| D5 | |
| D3, D4 | |
| <无> | 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 |
| <无> |
| D1 |
| <无> |
| D1 |
| D1 |
| <无> |
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 为导致此次导航的设备。
-
获取表示 referringDevice 且位于
navigator.bluetooth内的BluetoothDevice,并令 referringDeviceObj 为结果。 -
如果上一步抛出了异常,则中止这些步骤。
注:这意味着 UA 没有推断出用户有意授予 当前realm 对 referringDevice 的访问权限。例如, 用户可能已全局拒绝 GATT 访问。 -
将
navigator.bluetooth.设置为 referringDeviceObj。[[referringDevice]]
match,则蓝牙设备
device 匹配过滤器 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 尚未广播服务数据,其 UUID 的 128 位形式为serviceData"]serviceData["且其中的数据匹配service"]serviceData,则返回mismatch。 -
返回
match。
match,则字节数组 data 匹配
一个 BluetoothDataFilterInit
filter。
-
令 expectedPrefix 为
filter.所持字节的副本。dataPrefix -
如果 data 的字节数少于 expectedPrefix,则返回
mismatch。 -
对于 mask 中的每个
1位,如果 data 中对应的位 不等于 expectedPrefix 中对应的位,则返回mismatch。 -
返回
match。
true,则一个 BluetoothDataFilterInit
filter1 是另一个 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",则返回 一个被拒绝的 promise,其拒绝原因为一个
SecurityError。 -
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
令 devices 为一个新的空
Array。 -
对于
storage.中的每个 allowedDevice, 将表示 allowedDevice@allowedDevices[[device]]的BluetoothDevice对象添加到 devices。
注:devices 中的BluetoothDevice可能不在蓝牙无线电的 范围内。对于 devices 中的给定 device, 可使用watchAdvertisements()方法观察 device 何时处于范围内并广播广播数据包。当advertisementreceived事件 event 在 device 上触发时,它可能 表明该设备已经足够接近,可以通过调用event.device.gatt.建立连接。connect() -
-
返回 promise。
requestDevice(options)
方法在被调用时,必须运行以下步骤:
-
如果
options.存在 ,并且exclusionFiltersoptions.不存在, 则返回 一个被拒绝的 promise,其拒绝原因为一个filtersTypeError。 -
如果
options.存在,并且filtersoptions.为acceptAllDevicestrue, 或者如果options.不存在 并且filtersoptions.为acceptAllDevicesfalse,则返回 一个被拒绝的 promise,其拒绝原因为一个TypeError。注:这会强制要求filters或恰好存在其中一个。acceptAllDevices:true -
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
请求蓝牙设备,如果
options.为acceptAllDevicesfalse,则传入options., 否则传入filtersnull;如果options.存在则传入它,否则传入exclusionFiltersnull;并传入options.和optionalServicesoptions., 并令 devices 为结果。optionalManufacturerData -
在蓝牙任务源上排入一个全局任务,给定 this 的 相关全局对象,以运行以下 步骤:
-
如果上一步抛出异常,则使用该 异常拒绝 promise 并中止这些步骤。
-
如果 devices 是空序列,则以
NotFoundError拒绝 promise 并中止这些步骤。 -
使用
devices[0]兑现 promise。
-
-
-
返回 promise。
BluetoothPermissionStorage
storage 和一个
BluetoothLEScanFilterInit
序列
filters(可以为 null,表示
所有设备均可匹配)、一个 BluetoothLEScanFilterInit
序列
exclusionFilters(如果没有设置排除过滤器,可以为 null)、
一个 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,则对于 exclusionFilters 中的每个 exclusionFilter,执行以下步骤:-
令 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 的可导航对象。
-
令 promptId 为一个新的唯一不透明字符串。
实际上,
在提示打开期间,设备列表会动态更新。当前规范文本
未反映这一点,但此事件可能会使用相同的 promptId
和新的设备列表触发多次。参见
https://github.com/WebBluetoothCG/web-bluetooth/issues/621。
-
给定 navigable、promptId 和 scanResult, 触发提示更新事件。
-
即使 scanResult 为空, 也提示用户选择 scanResult 中与 descriptor 关联的设备之一,并令 device 为结果。
UA 可以允许用户选择附近不匹配 uuidFilters 的设备。
注:UA 应向用户显示每个设备的人类可读名称。 如果该名称不可用,例如因为 UA 的蓝牙 系统不支持启用隐私的扫描,则 UA 应允许用户 表示兴趣,然后执行禁用隐私的扫描以检索 名称。 -
从可导航对象到设备 提示的映射[navigable 的可导航对象 ID] 中移除。
-
UA 可以将 device 添加到 storage。
注:选择 device 很可能表明用户 希望该设备至少在当前设置 对象的 "bluetooth" 额外权限数据的allowedDevices列表中出现,使其mayUseGATT字段为true,使 requiredServiceUUIDs 和 optionalServiceUUIDs 并集中的所有服务都出现在其allowedServices列表中,此外 还保留已经存在的任何服务,并使 optionalManufacturerData 中的制造商代码出现在其allowedManufacturerData列表中。 -
如果 device 为“
denied”, 则返回[]并中止这些步骤。 -
UA 可以使用 device 内的所有服务填充蓝牙缓存。 忽略此步骤产生的任何错误。
-
在 this 内获取表示 device 的
BluetoothDevice, 传播任何异常,并令 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 为一个由0xFF字节组成、长度与 dataPrefix 相同的序列。 -
如果 mask 与 dataPrefix 的长度不同,则抛出
TypeError并中止这些步骤。 -
返回
{dataPrefix: new Uint8Array(|dataPrefix|), mask: new Uint8Array(|mask|)}。
-
如果 UA 最近使用一个 UUID 集合扫描过设备,而该集合是 当前扫描 UUID 的超集,则 UA 可以返回该 扫描的结果并中止这些步骤。
-
令 simulatedBluetoothDevices 为一个空列表。
-
如果 topLevelTraversable 具有模拟 蓝牙适配器,则令 simulatedBluetoothDevices 为其模拟蓝牙设备映射的值。
-
如果 UA 支持 LE 传输,则执行通用 发现 过程,但 UA 可以包含未设置 可发现 模式标志的设备,并将发现的蓝牙 设备添加到 nearbyDevices。UA 应启用隐私 功能。
被动 扫描和隐私功能都能避免 泄露唯一且不可变的设备 ID。我们应当要求 UA 使用 两者之一,但似乎没有任何操作系统 API 暴露其中任一种。蓝牙还 使得被动扫描难以使用,因为它并不要求 中心设备支持 观察过程。
-
令 result 为一个初始为空的蓝牙设备集合。
-
对于 nearbyDevices 和 simulatedBluetoothDevices 中的每个 蓝牙设备 device,执行以下子步骤:
-
如果 device 的支持的物理传输包含 LE 且其蓝牙设备名称是部分名称或不存在, 则 UA 应执行名称发现过程以获取 完整名称。
-
如果 device 广播的服务 UUID与 服务 UUID 集合存在非空 交集,则将 device 添加到 result 并中止这些子步骤。
注:对于 BR/EDR 设备,在扩展查询响应中无法区分 GATT 服务和非 GATT 服务。如果站点 使用非 GATT 服务的 UUID 进行过滤,则用户可能能够 为requestDevice的结果选择一个设备,而此 API 没有提供与该设备交互的方法。 -
UA 可以连接到 device,并使用 UUID 位于 服务 UUID 集合中的所有服务填充蓝牙 缓存。如果 device 的支持的物理 传输包含 BR/EDR,则除了标准 GATT 过程外,UA 在填充缓存时还可以使用服务发现协议(搜索 服务)。
-
如果蓝牙缓存包含 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. Permission 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( "权限已丢失" , "NotFoundError" ); } }). then(...);
Web Bluetooth API 是一个由
强大功能,其
名称为
"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实例与另一个时刻看到的另一个BluetoothDevice实例是否表示同一设备,而后者可能位于 不同的realm 中。在返回 "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。
-
-
在
global.navigator.bluetooth中获取表示allowedDevice.的[[device]]BluetoothDevice,并将 结果添加到 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 的蓝牙任务源上排入一个全局任务,以使用
false兑现 promise, 并中止这些步骤。 -
如果用户已将 UA 配置为让此函数针对当前源返回 特定答案,则排入一个 任务,以使用所配置的答案兑现 promise,并中止 这些步骤。
注:如果用户已阻止 Web Bluetooth 权限,UA 可以使用false兑现 promise。 -
令 simulatedBluetoothAdapter 为 this 的可导航对象的 顶级可遍历对象的模拟 蓝牙适配器。
-
如果 simulatedBluetoothAdapter 不为空,
-
如果 UA 正在具有蓝牙无线电的系统上运行,则无论蓝牙 无线电是否开启,都在给定 global 的蓝牙任务源上排入一个全局任务,以使用
true兑现 promise。 -
否则,在给定 global 的蓝牙任务源上排入一个全局任务,以使用
false兑现 promise。注:promise 会被并行兑现,以允许 UA 调用 其他系统来确定蓝牙是否可用。
getAvailability
promise,则可以使用以下代码
检测蓝牙何时再次可用,以显示蓝牙 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(); }; });
getAvailability()
返回答案的配置,
则 UA 必须对每个
全局对象 global,在给定该对象的蓝牙任务源上排入一个全局任务,以运行以下步骤:
-
令 oldAvailability 为变化前
getAvailability()本会返回的值。 -
令 newAvailability 为变化后
getAvailability()会返回的值。 -
如果 oldAvailability 与 newAvailability 不同,
-
令 navigator 为 global 的关联
Navigator。 -
令 bluetooth 为 navigator 的关联
Bluetooth。 -
在 bluetooth 上使用
ValueEvent接口触发一个名为availabilitychanged的事件,并将其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 需要在多个层级跟踪蓝牙设备属性:全局、 每个源以及每个全局对象。
5.1. 全局蓝牙设备属性
物理蓝牙设备可能保证具有某些 UA 尚未接收到的属性。这些属性在此被描述为可选属性。
一个蓝牙设备具有 以下属性。除非另有说明,否则可选 属性不存在,序列和映射属性为空。 其他属性具有指定的默认值,或者 在引入设备时指定。
-
一组支持的物理传输,包括 BR/EDR 和 LE 中的一种或两种。 通常会根据发现该设备时所使用的传输方式,以及 广播数据 或扩展查询响应中的标志数据类型来填充此集合。
-
一个可选的 128 位身份解析密钥。
-
一个可选的部分或完整蓝牙设备名称。当接收到缩短的本地名称 AD 数据, 但 尚未读取完整名称时,设备具有部分名称。蓝牙设备名称 使用 UTF-8 编码,并通过无 BOM 的 UTF-8 解码算法转换为 DOMString。
-
一个可选的ATT 承载, 所有 GATT 通信均通过它进行。ATT 承载由 GAP 互操作性要求中“连接 建立”所述的过程创建。它会以 [BLUETOOTH42]未完全明确说明的方式断开连接。
-
GATT 属性的层次结构。
当且仅当两个蓝牙设备具有相同的 公共 蓝牙地址、静态地址、私有 地址或身份解析密钥,或者使用一个设备的 IRK 和另一个设备的 可解析私有 地址成功执行可解析私有 地址解析过程时,UA 应确定它们是同一蓝牙 设备。但是,由于平台 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()
使页面能够撤销用户已授予的
对该设备的访问权限。
如果 UA 当前正在扫描来自此设备的
广播并为其触发事件,则 watchingAdvertisements 为 true。
BluetoothDevice
实例使用下表所述的内部槽
创建:
| 内部槽 | 初始值 | 描述(非规范性) |
|---|---|---|
[[context]]
| <始终在正文中设置> |
返回此 BluetoothDevice
的 Bluetooth
对象。
|
[[representedDevice]]
| <始终在正文中设置> |
此对象所表示的蓝牙
设备;
如果访问权限已被撤销,则为 null。
|
[[gatt]]
|
一个新的 BluetoothRemoteGATTServer
实例,其
device
属性初始化为 this,并且
其 connected
属性初始化为
false。
| 不会改变。 |
[[allowedServices]]
| <始终在正文中设置> |
此设备针对该
源的 allowedServices
列表;如果允许所有服务,则为 "all"。例如,UA 可以授予
某个源访问 referringDevice
上所有服务的权限,该设备曾广播
此源上的 URL。
|
[[allowedManufacturerData]]
| <始终在正文中设置> |
此设备针对
该源的 allowedManufacturerData
列表。
|
[[watchAdvertisementsState]]
| 'not-watching'
|
一个描述
watchAdvertisements()
操作当前状态的字符串枚举。可能的
枚举值为:
|
Bluetooth
实例
context 中获取
表示一个蓝牙设备
device 的 BluetoothDevice,UA 必须运行以下步骤:
-
令 storage(一个
BluetoothPermissionStorage)为 "bluetooth" 对当前设置对象的 额外权限数据。 -
在
storage.中查找 allowedDevice,其allowedDevicesallowedDevice.与 device 是同一设备。如果不存在这样的对象,则抛出[[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
属性必须执行以下步骤:
-
如果 "bluetooth" 对
this的相关 设置对象的额外权限数据在其allowedDevices列表中具有一个AllowedBluetoothDeviceallowedDevice,其中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。 -
以
AbortError拒绝 promise。
-
-
-
如果
this.为:[[watchAdvertisementsState]]'not-watching'-
-
将
this.设置为[[watchAdvertisementsState]]'pending-watch'。 -
将以下步骤排入 广播监听管理器, 但当
this.变为[[watchAdvertisementsState]]not-watching时中止:-
确保 UA 正在扫描此设备的 广播。UA 不应过滤掉同一设备的“重复” 广播。
-
如果 UA 无法启用扫描,则在给定 global 的蓝牙任务源上排入一个全局任务以执行 以下步骤,并中止这些步骤:
-
将
this.设置为[[watchAdvertisementsState]]'not-watching'。 -
以下列错误之一拒绝 promise:
- UA 不支持扫描广播
- 蓝牙已关闭
- 其他原因
-
-
在给定 global 的蓝牙任务源上排入一个全局任务以执行以下步骤,但当
this.变为[[watchAdvertisementsState]]not-watching时中止:-
将
this.设置为[[watchAdvertisementsState]]watching。 -
将
this.设置为watchingAdvertisementstrue。 -
以
undefined兑现 promise。
-
-
-
'pending-watch'-
-
以
InvalidStateError拒绝 promise。
-
'watching'-
-
以
undefined兑现 promise。
-
-
如果已中止,则以
AbortError拒绝 promise。
注:扫描会消耗电力,因此网站应避免
不必要地监听广播,
并应使用其 AbortController
尽快停止电力
消耗。
BluetoothDevice
device 中止 watchAdvertisements,
运行以下步骤:
-
将
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. 处理可见性变化
发起蓝牙设备扫描的操作只能在可见的
文档中运行。当可见性状态不再为
"visible" 时,需要中止该文档
的扫描操作。
-
令 global 为 document 的相关全局对象。
-
在给定 global 的蓝牙任务源上排入一个全局任务, 以 执行以下步骤:
-
令 navigator 为 global 的关联
Navigator。 -
令 bluetooth 为 navigator 的关联
Bluetooth。 -
如果 visibilityState 不为
"visible",则在 bluetooth 上中止所有活动的 watchAdvertisements 操作。
-
5.2.2. 处理 Document 失去完全活动状态
发起蓝牙设备扫描的操作只能在完全活动的文档中运行。 当失去完全活动状态时,需要中止该文档的扫描 操作。
Document
不再完全活动时,必须运行以下步骤:
-
令 global 为 document 的相关全局对象。
-
在给定 global 的蓝牙任务源上排入一个全局任务, 以 执行以下步骤:
-
令 navigator 为 global 的关联
Navigator。 -
令 bluetooth 为 navigator 的关联
Bluetooth。 -
在 bluetooth 上运行中止所有活动的 watchAdvertisements 操作。
-
5.2.3. 响应广播事件
当一个广播
事件到达某个 BluetoothDevice,
且其 watchingAdvertisements
已设置时,
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
device 是发送此广播的 BluetoothDevice。
uuids 列出此广播所表明
device
的
GATT 服务器支持的服务 UUID。
name 是 device
的
本地名称或其前缀。
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 的iBeacon 如何工作?。
-
令 device 为发送该 广播事件的蓝牙设备。
-
对于 UA 中每个
BluetoothDevicedeviceObj,如果 device 与deviceObj.是同一设备, 则在 deviceObj 的相关设置对象的 负责的事件循环上排入一个 任务,以执行以下 子步骤:[[representedDevice]]-
如果
deviceObj.为watchingAdvertisementsfalse,则中止这些子步骤。 -
针对该广播事件,在 deviceObj 上触发一个
advertisementreceived事件。
-
BluetoothDevice
deviceObj 上触发一个 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 中的每个
uuid,如果它位于this.device.中,则 将[[allowedServices]]uuid追加到event.uuids。 - 缩短的本地名称
- 完整的本地名称
-
对 AD 数据执行无 BOM 的 UTF-8 解码,并
将
event.name设置为结果。注:我们不会暴露名称是否完整,因为现有 API 需要读取原始广播才能获取此信息, 而在向 API 添加字段之前,我们希望获得更多证据来证明它有用。 - 制造商特定数据
-
对于每个 16 位公司标识符代码
manufacturerCode,如果它位于this.device.中,并且制造商数据不是被阻止的制造商数据, 则向[[allowedManufacturerData]]event.manufacturerData添加从manufacturerCode到一个包含制造商特定数据的ArrayBuffer的映射。 - TX 功率 电平
-
将
event.txPower设置为 AD 数据。 - 服务数据
- 16 位 UUID
- 服务数据 - 32 位 UUID
- 服务数据 - 128 位 UUID
- 服务数据 - 32 位 UUID
-
对于服务数据中的每个UUID
uuid,如果它 位于this.device.中,则向[[allowedServices]]event.serviceData添加从 uuid 到一个 包含 服务数据的ArrayBuffer的映射。 - 外观
-
将
event.appearance设置为 AD 数据。 - 其他情况
- 跳到下一个 AD 结构。
-
16 位服务
UUID的不完整列表
-
在 deviceObj 上,使用
BluetoothAdvertisingEvent并以 event 初始化,触发一个名为“advertisementreceived”的事件, 并将其isTrusted属性初始化 为true。
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 信息模型
配置文件纯粹是逻辑上的:配置文件规范描述了 该配置文件所包含的其他 GATT 实体之间的预期交互,但 无法查询设备支持哪些配置文件。
GATT 客户端可以使用一组GATT 过程发现设备上的服务、 特征和描述符并与其交互。本规范将服务、特征和描述符 统称为属性。所有属性都有一个由 UUID 标识的类型。每个属性还 有一个 16 位属性 句柄,用于将其与同一 GATT 服务器上相同类型的其他属性区分开来。属性 在概念上按照其属性句柄在其GATT 服务器内排序,但虽然平台接口 会以某种顺序提供属性,却不能保证该顺序与属性 句柄顺序一致。
一个服务包含一组 包含服务和 特征。包含 服务是对其他服务的引用,并且单个服务可以被多个 其他服务包含。如果服务直接出现在 GATT 服务器下,则称为主 服务;如果仅被其他服务包含,则称为次级服务,不过主服务也可以被 包含。
一个特征包含一个 值(即字节数组)以及一组 描述符。根据 特征的属性, GATT 客户端 可以读取或写入其值,或者注册以便 在值发生变化时收到通知。
6.1.1. 跨连接持久化
蓝牙属性
缓存系统允许已绑定的客户端
保存从一次连接到下一次连接的属性引用。Web Bluetooth
将网站视为与其获准
访问的设备未绑定:BluetoothRemoteGATTService、
BluetoothRemoteGATTCharacteristic
和 BluetoothRemoteGATTDescriptor
对象会在
断开连接时失效,并且站点在重新连接时必须再次检索
它们。
6.1.2. 蓝牙缓存
UA 必须维护一个蓝牙缓存,其中保存其在
设备上发现的服务、特征和描述符的层次结构。UA 可以在访问同一
设备的多个源之间共享此缓存。缓存中的每个潜在条目都处于已知存在、已知不存在
或未知状态。缓存不得包含两个属于同一
属性的条目。缓存中每个已知存在的条目都与每个
Bluetooth
实例的一个可选
Promise<、
BluetoothRemoteGATTService>Promise<
或
BluetoothRemoteGATTCharacteristic>Promise<
实例相关联。
BluetoothRemoteGATTDescriptor>
serviceA.getCharacteristic(uuid1) 函数,UA 会使用按 UUID 发现特征
过程来填充所需的缓存条目,并且 UA 会提前结束该过程,
因为它只需要一个特征来兑现返回的 Promise,
那么 serviceA 内第一个 UUID 为 uuid1 的特征
为已知存在,而之后所有具有该 UUID 的特征仍为未知。如果用户之后调用
serviceA.getCharacteristics(uuid1),UA 需要恢复或
重新启动按 UUID 发现特征过程。如果最终发现
serviceA 只有一个 UUID 为
uuid1 的特征,那么后续特征将变为已知不存在。
蓝牙缓存中的已知存在条目是有序的:主 服务在设备中以特定顺序出现,包含服务和 特征在服务中以特定顺序出现,而描述符 在特征中以特定顺序出现。该顺序应与设备上属性 句柄的顺序一致,但如果设备的顺序不可用,UA 可以使用其他顺序。
-
尝试使缓存中所有匹配条目变为已知存在或 已知不存在,可以使用[BLUETOOTH42]所规定能够返回足够 信息的任意GATT 过程序列。按照 § 6.7 错误处理中的说明处理错误。
-
如果上一步返回错误,则从此算法返回该错误。
BluetoothDevice
实例
deviceObj 中查询
蓝牙缓存以查找与某个描述匹配的条目,UA 必须返回一个包裹
新的
promise promise 的
deviceObj.gatt-连接检查包装器,并并行运行以下步骤:
-
令 global 为 deviceObj 的相关全局对象。
-
使用与描述 匹配的条目填充蓝牙缓存。
-
如果上一步返回错误,则在给定 global 的 蓝牙任务源上排入一个全局任务,以使用该 错误拒绝 promise,并中止这些步骤。
-
令 entries 为与该 描述匹配的已知存在缓存条目的序列。
-
令 context 为 deviceObj.
[[context]]。 -
令 result 为一个新序列。
-
对于 entries 中的每个 entry:
-
如果 entry 没有关联的
Promise<BluetoothGATT*>实例位于 context.[[attributeInstanceMap]]中, 创建一个BluetoothRemoteGATTService,表示 entry, 创建一个BluetoothRemoteGATTCharacteristic表示 entry,或创建一个BluetoothRemoteGATTDescriptor,表示 entry, 具体取决于 entry 是 Service、Characteristic 还是 Descriptor,并添加从 entry 到所得Promise的映射,位于 context.[[attributeInstanceMap]]中。 -
将 context.
[[attributeInstanceMap]]中与 entry 关联的Promise<BluetoothGATT*>实例追加到 result。
-
-
排入一个全局任务 到 蓝牙任务源 (给定 global),以 兑现 promise,使用等待全部 result 元素所得的结果。
6.1.3. 遍历蓝牙层次结构
single: boolean,
uuidCanonicalizer: function,
uuid: 可选的
(DOMString or unsigned int),allowedUuids: 可选的
("all" or Array<DOMString>),child type: GATT 声明类型),
UA 必须执行以下步骤:
-
如果存在 uuid,则将其设置为 uuidCanonicalizer(uuid)。如果 uuidCanonicalizer 抛出异常,则返回以该异常 拒绝的 promise并中止这些步骤。
-
如果 uuid 存在且被阻止,则返回一个 被拒绝的 promise,拒绝原因为一个
SecurityError并中止这些步骤。 -
根据 attribute 的类型,令 deviceObj 为:
BluetoothDeviceattributeBluetoothRemoteGATTServiceattribute.deviceBluetoothRemoteGATTCharacteristicattribute.service.device
-
如果
deviceObj.gatt.为connectedfalse,则返回一个被拒绝的 promise,其拒绝原因为一个NetworkError并中止这些步骤。 -
如果 Represented(attribute) 为
null,则返回 一个被拒绝的 promise,其拒绝原因为一个InvalidStateError并中止这些步骤。注:当服务或 特征从设备中移除或因断开连接而失效,随后再次使用其对象时,就会发生这种情况。
-
在
deviceObj中查询蓝牙缓存以查找 满足以下条件的条目:-
位于 Represented(attribute) 内,
-
具有由 child type 描述的类型,
-
具有未被阻止的 UUID,
-
如果存在 uuid,则具有 UUID uuid,
-
如果存在 allowedUuids 且其不为
"all",则具有 allowedUuids 中的 UUID,并且 -
如果设置了 single 标志,则是其中第一个。
令 promise 为结果。
-
-
兑现后,对于 promise 以 result 兑现的情况,运行 以下步骤:
-
如果 result 为空,则抛出
NotFoundError。 -
否则,如果设置了 single 标志,则返回 result 的第一个(也是唯一的) 元素。
-
否则,返回 result。
-
6.1.4. 识别服务、特征和描述符
在检查两个服务、特征或描述符 a 和 b 是否为同一 属性时,如果 a 和 b 位于同一 设备内并具有相同的属性句柄,则 UA 应确定 它们相同,但 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
device 是运行
此服务器的设备。
当此实例连接到
this.device 时,connected 为 true。即使 UA 在物理上已连接,
它也可能为 false,例如当其他全局对象具有其他已连接的 BluetoothRemoteGATTServer
实例时。
当任何 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,则返回一个以“NetworkError”DOMException拒绝的 promise。 -
如果 UA 当前正在使用蓝牙系统,则可以返回一个以“
NetworkError”DOMException拒绝的 promise。实现可能能够避免此
NetworkError, 但目前站点需要将其对此 API 的使用串行化, 和/或为用户提供重试失败操作的方式。[Issue #188] -
令 promise 为一个新的 promise。
-
将 promise 添加到 this.
[[activeAlgorithms]]。 -
并行运行以下步骤:
-
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
给定 global 的 可导航对象和 this.
device,触发一个 GATT 连接尝试事件。 -
如果 this.
[[automatedGATTConnectionResponse]]为"not-expected", 则将其设置为"expected"。 -
如果 this.
[[automatedGATTConnectionResponse]]为"expected", 则等待它发生变化。 -
令 response 为 this.
[[automatedGATTConnectionResponse]]。 -
将 this.
[[automatedGATTConnectionResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行 以下子步骤:-
从 this.
[[activeAlgorithms]]中移除 promise。 -
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果 this.
device.[[representedDevice]]没有ATT 承载,则执行以下子步骤:-
尝试使用 GAP 互操作性 要求中“连接建立”所述的过程创建ATT 承载。 如果 promise 从 this.
[[activeAlgorithms]]中移除,则中止此尝试。注:如果未收到可连接的广播, 这些过程可能会永远等待。 如果网站不再希望连接,则应调用disconnect()。 -
如果此尝试因为 promise 从 this.
[[activeAlgorithms]]中移除而中止,则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“AbortError”DOMException拒绝 promise 并中止这些 步骤。 -
如果此尝试因其他原因失败,则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止 这些步骤。 -
使用交换 MTU过程协商 支持的最大 MTU。忽略此步骤产生的任何错误。
-
UA 可以尝试使用BR/EDR 绑定过程或LE 绑定过程与远程设备绑定。
注:通常我们 更希望让网站控制 是否以及何时进行绑定,但 Core Bluetooth 平台 API 并未提供让 UA 实现这种控制项的方法。 已绑定比未绑定更安全,因此本 规范允许 UA 在可行的平台上伺机创建绑定。 这可能会导致在创建连接时出现用户可见的 配对对话框,而不是在访问受限特征时出现。
-
-
-
在给定 global 的蓝牙任务源上排入一个全局任务, 以执行以下子步骤:
-
如果 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。
-
如果未使用此 API 的系统(无论位于 UA 内部还是外部) 正在使用 device 的ATT 承载,则中止此算法。
-
对于整个 UA 中的所有
BluetoothDevicedeviceObj:-
如果
deviceObj.与 device 不是 同一设备,则继续处理下一个 deviceObj。[[representedDevice]] -
如果
deviceObj.gatt.为connectedtrue,则中止此算法。 -
如果
deviceObj.gatt.包含调用[[activeAlgorithms]]connect()所产生的Promise, 则中止此 算法。
-
-
销毁 device 的ATT 承载。
BluetoothRemoteGATTServer
被断开连接,则算法需要失败,即使 UA 整个
期间始终保持连接,并且 BluetoothRemoteGATTServer
随后在算法完成之前重新连接也是如此。我们包装返回的 Promise
来实现这一点。
要围绕一个 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.中,则返回 一个以[[allowedServices]]SecurityError拒绝的 promise 并中止这些步骤。 -
返回 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.中,则返回 一个以[[allowedServices]]SecurityError拒绝的 promise 并中止这些步骤。 -
返回 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 服务,即一组
特征以及与其他服务的关系,它们封装了
设备某一部分的行为。
[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 ;
device 是表示该 GATT 服务所属
远程外围设备的 BluetoothDevice。
uuid 是该
服务的 UUID,例如,心率服务的 UUID 为
'0000180d-0000-1000-8000-00805f9b34fb'。
isPrimary 指示
此服务的类型是主服务还是
次级服务。
BluetoothRemoteGATTService
实例使用下表所述的内部
槽创建:
| 内部槽 | 初始值 | 描述(非规范性) |
|---|---|---|
[[representedService]]
| <始终在正文中设置> |
此对象所表示的服务,
如果该服务已被移除或以其他方式失效,则为 null。
|
BluetoothRemoteGATTService,UA 必须运行以下步骤:
-
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
令 result 为一个新的
BluetoothRemoteGATTService实例,并将其[[representedService]]槽初始化为 service。 -
获取表示 service 所在设备的
BluetoothDevice,并令 device 为结果。 -
如果上一步抛出错误,则在给定 global 的蓝牙任务源上排入一个全局任务,以使用 该错误拒绝 promise 并中止这些步骤。
-
使用 device 初始化 result.
device。 -
使用 service 的 UUID 初始化 result.
uuid。 -
如果 service 是主服务,则将 result.
isPrimary初始化为true。否则, 将 result.isPrimary初始化为false。
-
-
返回 promise。
getCharacteristic(characteristic) 方法检索此
服务内的一个特征。调用时,它必须返回
GetGATTChildren(attribute=
this,
single=true,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")
getCharacteristics(characteristic) 方法检索此服务内的
特征列表。调用时,它必须返回
GetGATTChildren(attribute=
this,
single=false,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")
getIncludedService(service) 方法检索此服务内的一个
包含服务。调用时,它必须返回
GetGATTChildren(attribute=
this,
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")
getIncludedServices(service) 方法检索此服务内的
包含服务列表。调用时,它必须返回
GetGATTChildren(attribute=
this,
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")
6.4. BluetoothRemoteGATTCharacteristic
BluetoothRemoteGATTCharacteristic
表示一个 GATT 特征,
它是一个基本数据元素,可提供有关
外围设备服务的更多信息。
[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 ;
service 是此特征所属的 GATT
服务。
uuid 是该
特征的 UUID,例如
心率测量特征的 UUID 为
'00002a37-0000-1000-8000-00805f9b34fb'。
properties 保存此
特征的属性。
value 是当前缓存的
特征值。当读取该特征的值,或者通过
通知或指示更新该值时,此值会被更新。
BluetoothRemoteGATTCharacteristic
实例使用下表所述的
内部槽创建:
| 内部槽 | 初始值 | 描述(非规范性) |
|---|---|---|
[[representedCharacteristic]]
| <始终在正文中设置> |
此对象所表示的特征,如果该
特征已被移除或以其他方式失效,则为 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 所在服务的
BluetoothRemoteGATTService实例初始化 result.service<。 -
使用 characteristic 的 UUID 初始化 result.
uuid。 -
创建 一个
BluetoothCharacteristicProperties实例,该实例来自 特征 characteristic,并令 properties 为 结果。 -
如果上一步返回错误,则在给定 global 的蓝牙任务源上排入一个全局任务,以使用 该错误拒绝 promise 并中止这些步骤。
-
将 result.
properties初始化为 properties。 -
将 result.
value初始化为null。如果 characteristic 最近读取的值可用,UA 可以将 result.value初始化为一个新的DataView,该对象包装一个包含 characteristic 最近读取值的新的ArrayBuffer。
-
-
返回 promise。
getDescriptor(descriptor) 方法检索此
特征内的一个描述符。调用时,它必须返回
GetGATTChildren(attribute=
this,
single=true,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")
getDescriptors(descriptor) 方法检索此
特征内的描述符列表。调用时,它必须返回
GetGATTChildren(attribute=
this,
single=false,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")
readValue()
方法在被调用时,必须运行以下步骤:
-
如果 this.
uuid被阻止读取,则返回一个以“SecurityError”DOMException拒绝的 promise 并中止这些步骤。 -
如果 gatt.
connected为false,则返回一个以“NetworkError”DOMException拒绝的 promise 并中止这些步骤。 -
令 characteristic 为 this.
[[representedCharacteristic]]。 -
如果 characteristic 为
null,则返回一个以 “InvalidStateError”DOMException拒绝的 promise 并中止这些步骤。 -
返回一个包裹新的 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤:
-
如果 characteristic 的 属性中未设置
Read位,则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“NotSupportedError”DOMException拒绝 promise 并中止 这些步骤。 -
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
如果 this.
[[automatedCharacteristicReadResponse]]不为"not-expected",则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“InvalidStateError”DOMException拒绝 promise 并中止 这些步骤。 -
给定 global 的 可导航对象、this.
device、 characteristic 和read,触发一个模拟 特征事件。 -
将 this.
[[automatedCharacteristicReadResponse]]设置为"expected", 并等待它发生变化。 -
令 response 为 this.
[[automatedCharacteristicReadResponse]]。 -
将 this.
[[automatedCharacteristicReadResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。
-
-
否则,令 buffer 为一个新的
ArrayBuffer, 其中包含 this.[[automatedCharacteristicReadResponseData]]。
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,则可以在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并 中止这些步骤。实现可能能够避免此
NetworkError, 但目前站点需要将对此 API 的使用串行化,和/或为 用户提供重试失败操作的方式。[Issue #188] -
使用特征值读取 过程中的任意子过程组合来检索 characteristic 的值,并令 buffer 为一个保存所检索值的新的
ArrayBuffer。 按照§ 6.7 错误 处理中的说明处理错误。
-
-
在给定 global 的蓝牙任务源上排入一个全局任务, 以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则以“NetworkError”DOMException拒绝 promise 并中止 这些步骤。 -
如果上述子过程返回错误,则使用该错误拒绝 promise 并中止这些步骤。
-
在 this 上触发一个名为“
characteristicvaluechanged”的事件, 并将其bubbles属性初始化为true。
-
-
value: BufferSource,
response: string),
UA 必须执行以下步骤:
-
令 global 为 this 的相关全局对象。
-
如果 this.
uuid被阻止写入,则返回一个以“SecurityError”DOMException拒绝的 promise 并中止这些步骤。 -
令 bytes 为 value 所持字节的副本。
-
如果 bytes 的长度超过 512 字节(根据长属性值,这是属性 值的最大长度),则返回一个以 “
InvalidModificationError”DOMException拒绝的 promise 并中止这些步骤。 -
如果 gatt.
connected为false,则返回一个以“NetworkError”DOMException拒绝的 promise 并中止 这些步骤。 -
令 characteristic 为 this.
[[representedCharacteristic]]。 -
如果 characteristic 为
null,则返回一个以 “InvalidStateError”DOMException拒绝的 promise 并中止这些步骤。 -
返回一个包裹新的 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤。
-
断言:response 是 "required"、"never" 或 "optional" 之一。
-
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
如果 this.
[[automatedCharacteristicWriteResponse]]不为"not-expected",则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“InvalidStateError”DOMException拒绝 promise 并中止 这些步骤。 -
给定 global 的 可导航对象、this.
device、 characteristic、write和 bytes,触发一个模拟 特征事件。 -
将 this.
[[automatedCharacteristicWriteResponse]]设置为"expected", 并等待它发生变化。 -
令 response 为 this.
[[automatedCharacteristicWriteResponse]]。 -
将 this.
[[automatedCharacteristicWriteResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,则可以在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并 中止这些步骤。实现可能能够避免此
NetworkError, 但目前站点需要将对此 API 的使用串行化, 和/或为用户提供重试失败操作的方式。[Issue #188] -
通过执行 以下步骤将 bytes 写入 characteristic:
按照§ 6.7 错误处理中的说明处理错误。
-
-
使用蓝牙任务源在 global 上排入一个全局任务,以执行 以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则以“NetworkError”DOMException拒绝 promise 并中止 这些步骤。 -
如果上述过程返回错误,则使用该错误拒绝 promise 并中止这些步骤。
-
将 this.
value设置为一个 新的DataView, 它包装一个包含 bytes 的新的ArrayBuffer。 -
使用
undefined兑现 promise。
-
-
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 特征映射到一组
Bluetooth
对象,该集合称为该特征的活动
通知
上下文集合。
navigator.bluetooth
对象。当设备断开连接时,所有通知都会变为非活动状态。希望在
重新连接后继续接收通知的站点需要再次调用 startNotifications(),
而且在
startNotifications()
生效之前的间隙中,不可避免地存在遗漏某些通知的风险。
startNotifications() 方法在被调用时,必须运行以下
步骤。有关接收
通知的详细信息,请参见§ 6.6.4 响应通知和指示。
-
如果 this.
uuid被阻止读取,则返回一个以“SecurityError”DOMException拒绝的 promise。 -
如果 gatt.
connected为false,则返回一个以“NetworkError”DOMException拒绝的 promise。 -
令 characteristic 为 this.
[[representedCharacteristic]]。 -
如果 characteristic 为
null,则返回一个以 “InvalidStateError”DOMException拒绝的 promise。 -
返回一个包裹新的 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤。
-
如果 characteristic 的属性中既未设置
Notify位,也未设置Indicate位, 则在给定 global 的蓝牙任务源上排入一个全局任务, 以使用NotSupportedError拒绝 promise 并中止这些 步骤。 -
如果 characteristic 的活动通知上下文集合 包含
navigator.bluetooth, 则在给定 global 的蓝牙任务源上排入一个全局任务, 以使用 this 兑现 promise 并中止 这些步骤。 -
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
如果 this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]不为"not-expected",则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“InvalidStateError”DOMException拒绝 promise 并中止 这些步骤。 -
给定 global 的 可导航对象、this.
device、 characteristic 和subscribe-to-notifications,触发一个模拟 特征事件。 -
将 this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]设置为"expected", 并等待它发生变化。 -
令 response 为 this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]。 -
将 this.
[[automatedCharacteristicSubscribeToNotificationsResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。
-
-
否则,令 success 为
true。
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,则可以在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并 中止这些步骤。实现可能能够避免此
NetworkError, 但 目前站点需要将对此 API 的使用串行化,和/或为用户提供 重试失败操作的方式。[Issue #188] -
如果该特征具有客户端特征 配置 描述符,则使用任意特征描述符 过程,以 确保 characteristic 的客户端特征 配置 描述符中的
Notification或Indication位之一已设置,并符合 characteristic 的 属性约束。UA 应避免 同时设置两个位,并且如果两个位均已 设置,则必须对值变化事件去重。按照§ 6.7 错误 处理中的说明处理错误。注:某些设备具有这样的特征,其属性包含 Notify 或 Indicate 位,但没有客户端特征 配置描述符。这些不符合标准的特征 往往会无条件发送通知或指示,因此本 规范允许应用程序直接订阅其消息。 -
如果这些过程成功,则令 success 为
true。
-
-
如果 success 为
true,则将navigator.bluetooth添加到 characteristic 的活动通知上下文集合。 -
在给定 global 的蓝牙任务源上排入一个全局任务, 以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则以“NetworkError”DOMException拒绝 promise 并中止 这些步骤。 -
如果上述过程返回错误,则使用 该错误拒绝 promise 并中止这些步骤。
-
-
stopNotifications() 方法在被调用时,必须返回一个新的
promise promise,并并行运行以下步骤:
-
令 characteristic 为
this.。[[representedCharacteristic]] -
如果 characteristic 为
null,则返回一个以InvalidStateError拒绝的 promise 并中止这些步骤。 -
如果 characteristic 的活动通知上下文集合 包含
navigator.bluetooth, 则将其移除。-
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
如果 this.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]不为"not-expected",则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“InvalidStateError”DOMException拒绝 promise 并中止 这些步骤。 -
给定 global 的 可导航对象、this.
device、 characteristic 和unsubscribe-from-notifications,触发一个模拟 特征事件。 -
将 this.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]设置为"expected", 并等待它发生变化。 -
令 response 为 this.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]。 -
将 this.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。。
-
-
-
否则,运行以下步骤:
-
如果 characteristic 的活动通知上下文 集合变为 空,并且该特征具有客户端特征 配置描述符,则 UA 应使用任意特征 描述符过程来清除 characteristic 的客户端 特征配置描述符中的
Notification和Indication位。
-
-
6.4.1. BluetoothCharacteristicProperties
每个 BluetoothRemoteGATTCharacteristic
都通过 BluetoothCharacteristicProperties
对象公开其特征
属性。这些
属性表示哪些操作对该特征有效。
[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 的属性:
属性 位 broadcast广播 read读取 writeWithoutResponse无响应写入 write写入 notify通知 indicate指示 authenticatedSignedWrites已认证签名写入 -
如果特征属性的 Extended Properties 位未 设置,则将 propertiesObj.
reliableWrite和 propertiesObj.writableAuxiliaries初始化为false。否则,运行以下步骤:-
发现 characteristic 的特征扩展 属性描述符,并读取其 值到 extendedProperties 中。 按照§ 6.7 错误处理中的说明处理错误。
特征扩展 属性并未明确说明 对于给定特征,扩展属性是否不可变。 如果它们不可变,则应允许 UA 缓存它们。
-
如果上一步返回错误,则返回该错误。
-
根据 extendedProperties 的 Reliable Write 位初始化 propertiesObj.
reliableWrite。 -
根据 extendedProperties 的 Writable Auxiliaries 位初始化 propertiesObj.
writableAuxiliaries。
-
-
返回 propertiesObj。
6.5. BluetoothRemoteGATTDescriptor
BluetoothRemoteGATTDescriptor
表示一个 GATT 描述符,它
提供有关特征值的更多信息。
[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
characteristic 是
此描述符所属的 GATT 特征。
uuid 是
特征描述符的 UUID,例如
客户端特征配置描述符的 UUID 为
'00002902-0000-1000-8000-00805f9b34fb'。
value 是当前
缓存的描述符值。当读取描述符的值时,
此值会被更新。
BluetoothRemoteGATTDescriptor
实例使用下表所述的内部
槽创建:
| 内部槽 | 初始值 | 描述(非规范性) |
|---|---|---|
[[representedDescriptor]]
| <始终在正文中设置> |
此对象所表示的描述符,
如果该描述符
已被移除或以其他方式失效,则为 null。
|
[[automatedDescriptorReadResponse]]
| "not-expected"
| GATT 描述符读取尝试的模拟 GATT 描述符 响应代码。 |
[[automatedDescriptorReadResponseData]]
| 空字节序列 | GATT 描述符读取尝试的模拟 GATT 描述符 响应数据。 |
[[automatedDescriptorWriteResponse]]
| "not-expected"
| GATT 描述符写入尝试的模拟 GATT 描述符 响应代码。 |
BluetoothRemoteGATTDescriptor
描述符 descriptor,
UA 必须运行以下步骤。
-
令 promise 为一个新的 promise。
-
并行运行以下步骤:
-
令 result 为一个新的
BluetoothRemoteGATTDescriptor实例,并将其[[representedDescriptor]]槽初始化为 descriptor。 -
使用表示 descriptor 所在特征的
BluetoothRemoteGATTCharacteristic实例初始化 result.characteristic。 -
使用 descriptor 的 UUID 初始化 result.
uuid。 -
将 result.
value初始化为null。 如果 descriptor 最近读取的值 可用,UA 可以将 result.value初始化为一个新的DataView, 它包装一个新的ArrayBuffer, 其中包含 descriptor 最近读取的值。
-
-
返回 promise。
readValue() 方法在被调用时,必须运行以下步骤:
-
令 gatt 为 this.
characteristic.service.device.gatt。 -
如果 this.
uuid被阻止读取,则返回一个以“SecurityError”DOMException拒绝的 promise。 -
如果 gatt.
connected为false,则返回一个以“NetworkError”DOMException拒绝的 promise。 -
令 descriptor 为 this.
[[representedDescriptor]]。 -
如果 descriptor 为
null,则返回一个以 “InvalidStateError”DOMException拒绝的 promise。 -
返回一个包裹新的 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤:
-
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
如果 this.
[[automatedDescriptorReadResponse]]不为"not-expected",则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“InvalidStateError”DOMException拒绝 promise 并中止 这些步骤。 -
给定 global 的 可导航对象、this.
device、 descriptor 和read,触发一个模拟 描述符事件。 -
将 this.
[[automatedDescriptorReadResponse]]设置为"expected", 并等待它发生变化。 -
令 response 为 this.
[[automatedDescriptorReadResponse]]。 -
将 this.
[[automatedDescriptorReadResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。
-
-
否则,令 buffer 为一个新的
ArrayBuffer, 其中包含 this.[[automatedDescriptorReadResponseData]]。
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,则可以在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并 中止这些步骤。实现可能能够避免此
NetworkError, 但目前站点需要将对此 API 的使用串行化, 和/或为用户提供重试失败操作的方式。[Issue #188] -
使用读取特征 描述符或读取长特征 描述符子过程来检索 descriptor 的值,并令 buffer 为一个新的
ArrayBuffer, 其中保存 检索到的值。按照 § 6.7 错误处理中的说明处理错误。
-
-
在给定 global 的蓝牙任务源上排入一个全局任务, 以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则以“NetworkError”DOMException拒绝 promise 并中止 这些步骤。 -
如果上述子过程返回错误,则使用该错误拒绝 promise 并中止这些步骤。
-
-
writeValue(value) 方法在被调用时,必须运行
以下步骤:
-
令 gatt 为 this.
characteristic.service.device.gatt。 -
如果 this.
uuid被阻止写入,则返回一个以“SecurityError”DOMException拒绝的 promise。 -
令 bytes 为 value 所持字节的副本。
-
如果 bytes 的长度超过 512 字节(根据长属性值,这是属性 值的最大长度),则返回一个以 “
InvalidModificationError”DOMException拒绝的 promise。 -
如果 gatt.
connected为false,则返回一个以“NetworkError”DOMException拒绝的 promise。 -
令 descriptor 为 this.
[[representedDescriptor]]。 -
如果 descriptor 为
null,则返回一个以 “InvalidStateError”DOMException拒绝的 promise。 -
返回一个包裹新的 promise promise 的 gatt-连接检查包装器,并并行运行以下步骤。
-
如果 global 的可导航对象的 顶级可遍历对象的模拟蓝牙适配器 不为空,则运行以下步骤:
-
如果 this.
[[automatedDescriptorWriteResponse]]不为"not-expected",则在给定 global 的蓝牙任务源上排入一个全局任务,以使用“InvalidStateError”DOMException拒绝 promise 并中止 这些步骤。 -
给定 global 的 可导航对象、this.
device、 descriptor、write和 bytes,触发一个模拟 描述符事件。 -
将 this.
[[automatedDescriptorWriteResponse]]设置为"expected", 并等待它发生变化。 -
令 response 为 this.
[[automatedDescriptorWriteResponse]]。 -
将 this.
[[automatedDescriptorWriteResponse]]设置为"not-expected"。 -
如果 response 不为
0,则执行以下子步骤:-
在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并中止这些步骤。
-
-
-
否则,运行以下步骤:
-
如果 UA 当前正在使用蓝牙系统,则可以在给定 global 的蓝牙任务源上排入一个全局任务,以使用“
NetworkError”DOMException拒绝 promise 并 中止这些步骤。实现可能能够避免此
NetworkError, 但目前站点需要将对此 API 的使用串行化, 和/或为用户提供重试失败操作的方式。[Issue #188] -
使用写入特征 描述符或写入长特征 描述符子过程,将 bytes 写入 descriptor。按照 § 6.7 错误处理中的说明处理错误。
-
-
在给定 global 的蓝牙任务源上排入一个全局任务, 以执行以下步骤:
-
如果 promise 不在 gatt.
[[activeAlgorithms]]中,则以“NetworkError”DOMException拒绝 promise 并中止 这些步骤。 -
如果上述子过程返回错误,则使用该错误拒绝 promise 并中止这些步骤。
-
将 this.
value设置为一个新的DataView, 它包装一个新的ArrayBuffer, 其中包含 bytes。 -
使用
undefined兑现 promise。
-
-
6.6. 事件
6.6.1. 蓝牙树
蓝牙树是指
navigator.bluetooth
和实现
BluetoothDevice、
BluetoothRemoteGATTService、
BluetoothRemoteGATTCharacteristic
或 BluetoothRemoteGATTDescriptor
接口的对象参与树时所构成的结构。
-
navigator.bluetooth的子节点是表示 "bluetooth" 对navigator.bluetooth的 相关设置 对象的额外权限数据中的allowedDevices列表中的设备的BluetoothDevice对象,其顺序未指定。 -
一个
BluetoothDevice的子节点是 表示其 GATT 服务器上主服务和次级 服务的BluetoothRemoteGATTService对象,这些服务的 UUID 位于源和 设备的allowedServices列表中。主 服务的顺序必须与 按服务 UUID 发现主服务过程返回的顺序一致,但次级 服务以及 UUID 不同的主服务可以按任意顺序排列。 -
一个
BluetoothRemoteGATTService的子节点是 表示其 特征的BluetoothRemoteGATTCharacteristic对象。特征的顺序必须与 按 UUID 发现特征 过程返回的顺序一致, 但 UUID 不同的特征可以按任意顺序排列。 -
一个
BluetoothRemoteGATTCharacteristic的子节点是 表示其描述符的BluetoothRemoteGATTDescriptor对象,其顺序与发现所有特征 描述符 过程返回的顺序一致。
6.6.2. 事件类型
-
advertisementreceived -
当从某个设备接收到
广播事件时,在该
BluetoothDevice上触发。 availabilitychanged-
当
整个蓝牙系统对 UA
变为可用或不可用时,在
navigator.bluetooth上触发。 -
characteristicvaluechanged -
当一个
BluetoothRemoteGATTCharacteristic的值发生变化时触发, 其变化可能源于 读取请求,或者 值变化通知/指示。 -
gattserverdisconnected -
当
活动 GATT 连接丢失时,在一个
BluetoothDevice上触发。 -
serviceadded -
当在远程
设备上发现一个新的服务时,就在其被添加到蓝牙树之后,在新的
BluetoothRemoteGATTService上触发。 -
servicechanged -
当一个
BluetoothRemoteGATTService的状态发生变化时触发。 这包括向服务添加或 从服务中移除任何特征和/或描述符,以及来自 远程设备的服务已更改指示。 -
serviceremoved -
当一个
BluetoothRemoteGATTService从其设备中移除时,就在其从蓝牙 树中移除之前触发。
6.6.3. 响应断开连接
BluetoothDevice
deviceObj,UA 必须在给定
deviceObj 的相关全局对象的蓝牙任务源上排入一个全局任务,以执行以下步骤:
-
如果
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 具有客户端特征 配置描述符,则 UA 应使用任意 特征描述符过程 清除 characteristic 的客户端特征 配置 描述符中的[[representedDevice]]Notification和Indication位。 -
将
characteristic.设置为[[representedCharacteristic]]null。
-
-
对于 deviceObj 的 realm 中的每个
BluetoothRemoteGATTDescriptordescriptor,将descriptor.设置为[[representedDescriptor]]null。 -
在
deviceObj上触发一个名为gattserverdisconnected的事件,并将其bubbles属性初始化为true。注:此事件不会在BluetoothRemoteGATTServer上触发。
6.6.4. 响应通知和指示
-
对于特征的活动 通知上下文集合中的每个 bluetoothGlobal,在给定 bluetoothGlobal 的相关全局对象的蓝牙任务源上排入一个全局任务,以执行以下 子步骤:
-
令 characteristicObject 为 以 bluetoothGlobal 为根的蓝牙树中表示该 特征的
BluetoothRemoteGATTCharacteristic。 -
如果
characteristicObject .service.device.gatt.为connectedfalse,则中止这些子步骤。 -
将
characteristicObject.value设置为一个新的DataView, 它包装一个新的ArrayBuffer, 其中保存 特征的新值。 -
在 characteristicObject 上触发一个名为
characteristicvaluechanged的事件,并将其bubbles属性初始化为true。
-
6.6.5. 响应服务变更
-
令 removedAttributes 为 UA 在收到指示 之前已发现的、位于服务已更改特征所指示范围内的属性列表。
-
使用主服务发现、关系发现、 特征发现和特征描述符 发现过程,重新发现服务已更改特征所指示范围内的属性。 如果 UA 能证明发现结果 不会影响下方触发的事件,则可以跳过发现所指示范围的全部或一部分。
-
令 addedAttributes 为上一步中发现的属性列表。
-
如果一个具有相同定义(参见服务互操作性 要求)的属性(忽略特征值和描述符值)同时出现在 removedAttributes 和 addedAttributes 中,则将其 从两者中移除。
给定以下设备状态:- 状态 1
-
-
服务 A
- 特征 C:值
[1, 2, 3]
- 特征 C:值
- 服务 B
-
服务 A
- 状态 2
-
-
服务 A
- 特征 C:值
[3, 2, 1]
- 特征 C:值
- 服务 B
-
服务 A
- 状态 3
-
-
服务 A
- 特征 D:值
[3, 2, 1]
- 特征 D:值
- 服务 B
-
服务 A
- 状态 4
-
-
服务 A
- 特征 C:值
[1, 2, 3]
- 特征 C:值
-
服务 B
- 包含服务 A
-
服务 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,在其负责的事件循环上排入一个 任务,以执行以下 子步骤:
-
对于每个
BluetoothRemoteGATTServiceservice,如果其相关 设置对象为 settings,并且service.位于 invalidatedAttributes 中,则将[[representedService]]service.设置为[[representedService]]null。 -
对于每个
BluetoothRemoteGATTCharacteristiccharacteristic,如果其 相关设置对象为 settings,并且characteristic.位于 invalidatedAttributes 中,则将[[representedCharacteristic]]characteristic.设置为[[representedCharacteristic]]null。 -
对于每个
BluetoothRemoteGATTDescriptordescriptor,如果其相关 设置对象为 settings,并且descriptor.位于 invalidatedAttributes 中,则将[[representedDescriptor]]descriptor.设置为[[representedDescriptor]]null。 -
令 global 为 settings 的 全局对象。
-
从
global.navigator.bluetooth.中移除表示 invalidatedAttributes 中属性的 每个条目。[[attributeInstanceMap]]
-
-
令 changedServices 为一个初始为空的服务集合。
-
如果同一 服务同时出现在 removedAttributes 和 addedAttributes 中,则将其从两者中移除,并添加到 changedServices 中。
-
对于 removedAttributes 或 addedAttributes 中的每个特征和描述符,将其从原始列表中移除,并将其 父服务添加到 changedServices 中。
注:从此处开始,removedAttributes 和 addedAttributes 仅包含服务。 -
如果 addedAttributes 中的一个服务在此前任何一次
getPrimaryService、getPrimaryServices、getIncludedService或getIncludedServices调用时即使 已经存在也不会被返回,则 UA 可以从 addedAttributes 中移除该服务。 -
令 changedDevices 为包含 removedAttributes、 addedAttributes 和 changedServices 中任一服务的蓝牙设备集合。
-
对于连接到 changedDevices 中某个设备的每个
BluetoothDevicedeviceObj,在给定 deviceObj 的相关全局对象的蓝牙任务源上排入一个全局任务,以执行以下 步骤:-
对于 removedAttributes 中的每个服务 service:
-
如果
deviceObj.为[[allowedServices]]"all"或包含该服务的 UUID,则在 表示该服务的BluetoothRemoteGATTService上触发一个事件, 该事件名为serviceremoved, 并将其bubbles属性 初始化为true。
-
-
对于 addedAttributes 中的每个服务,如果
deviceObj.为[[allowedServices]]"all"或包含该服务的 UUID,则将表示此服务的BluetoothRemoteGATTService添加到 蓝牙树,然后在该BluetoothRemoteGATTService上触发一个名为serviceadded的事件,并将其bubbles属性初始化为true。 -
对于 changedServices 中的每个服务,如果
deviceObj.为[[allowedServices]]"all"或包含该服务的 UUID,则在表示 该服务的BluetoothRemoteGATTService上触发一个名为servicechanged的事件,并将其bubbles属性初始化 为true。
-
6.6.6. IDL 事件处理器
[SecureContext ]interface mixin {CharacteristicEventHandlers attribute EventHandler oncharacteristicvaluechanged ; };
oncharacteristicvaluechanged 是用于
characteristicvaluechanged
事件类型的事件处理器 IDL 属性。
[SecureContext ]interface mixin {BluetoothDeviceEventHandlers attribute EventHandler onadvertisementreceived ;attribute EventHandler ongattserverdisconnected ; };
onadvertisementreceived
是用于 advertisementreceived
事件
类型的事件处理器 IDL 属性。
ongattserverdisconnected
是用于 gattserverdisconnected
事件类型的事件处理器 IDL 属性。
[SecureContext ]interface mixin {ServiceEventHandlers attribute EventHandler onserviceadded ;attribute EventHandler onservicechanged ;attribute EventHandler onserviceremoved ; };
onserviceadded 是用于 serviceadded
事件类型的事件
处理器 IDL 属性。
onservicechanged 是用于 servicechanged
事件类型的事件
处理器 IDL 属性。
onserviceremoved 是用于 serviceremoved
事件类型的事件
处理器 IDL 属性。
6.7. 错误处理
错误
响应时,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 过程为写入,
则从该步骤返回一个
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
Bluetooth SIG 在 [BLUETOOTH-ASSIGNED] 中维护一个 UUID 注册表,用于 标识服务、特征、描述符和其他实体。本 节提供了一种让脚本按名称查找这些 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 为在
'\n'处分割 contents 的结果。 -
令 result 为一个空映射。
-
对于 lines 中的每个 line,执行以下子步骤:
-
返回 result。
GATT 分配 服务是在 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt 处解析 GATT 分配编号的结果。 UA 应定期重新获取此文件,但未规定具体频率。
GATT 分配特征是在 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_characteristics.txt 处解析 GATT 分配编号的结果。 UA 应定期重新获取此文件,但未规定具体频率。
GATT 分配 描述符是在 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_descriptors.txt 处解析 GATT 分配编号的结果。 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。公司标识符的官方列表可在
蓝牙分配编号网站上找到。
BluetoothDataFilterInit
列表的映射,
或一个错误,
由以下算法产生:
-
获取 url,并令 contents 为其按 UTF-8 解码的正文。
-
令 lines 为在 contents 上以分隔符
'\n'调用split(separator, limit)所得的结果。 -
令 result 为一个空映射。
-
对于 lines 中的每个 line,执行以下子步骤:
-
如果 line 为空,或其第一个字符为
'#',则继续处理 下一行。 -
令 regExp 为一个以 'manufacturer\ ([0-9a-f]+)\ ([0-9a-f]+\/[0-9a-f]+)' 构造的
RegExp。 -
令 matchResult 为在 line 上调用 regExp.
exec(string)所得的结果;如果 matchResult 为null,或 matchResult 的长度不等于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 为在
'\n'处分割 contents 的结果。 -
令 result 为一个空映射。
-
对于 lines 中的每个 line,执行以下子步骤:
-
返回 result。
GATT 阻止列表是在 https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt 处解析 GATT 阻止列表的结果。 制造商 数据阻止列表是在 https://github.com/WebBluetoothCG/registries/blob/master/manufacturer_data_blocklist.txt 处解析制造商数据阻止列表的结果。 UA 应定期重新获取阻止列表,但未规定具体频率。
如果GATT 阻止列表的
值为错误,或 UUID 在GATT
阻止列表中映射到“exclude”,则一个 UUID
被阻止。
如果GATT
阻止列表的值为错误,或 UUID 在GATT
阻止列表中映射到
“exclude”或“exclude-reads”之一,则一个 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 必须设置为一个新的 Bluetooth
对象,
该对象在 Navigator
对象的相关 realm中创建。
Navigator
的
bluetooth getter
步骤是返回 this 的关联的
Bluetooth。
11. 集成
11.1. 权限策略
本规范定义了一个由标记“bluetooth”标识的策略控制功能,
该功能控制是否可以使用 Navigator
对象上的 bluetooth
属性所公开的方法。
此功能的默认允许列表为
["self"]。
12. 自动化测试
出于用户代理自动化和应用程序测试的目的,本文档定义了对 [WebDriver-BiDi] 规范的扩展。
Web Bluetooth API 及其扩展规范给测试作者带来了挑战,因为要完整测试 这些接口,需要能够以可预测方式响应的物理硬件设备。为解决此 挑战,本文档定义了多个 WebDriver-BiDi 扩展命令,用于定义和 控制行为类似于物理外围设备及其广播的模拟外围设备和广播。 这些模拟外围设备和广播表示具有特定属性的设备, 其读数可完全由用户定义。
每个顶级可遍历对象都可以具有一个模拟蓝牙适配器,它是一个软件 定义的蓝牙适配器,具有一组已发现的模拟蓝牙 设备,并且可以承担诸如中心设备之类的角色。
每个模拟蓝牙适配器都有一个模拟蓝牙设备
映射,它是一个从蓝牙地址 字符串
到模拟蓝牙设备的有序映射。
每个模拟蓝牙适配器都有一个适配器状态,它是一个 描述适配器当前状态的字符串枚举。可能的枚举值为:
-
"powered-on"
-
"powered-off"
-
"absent"
每个模拟蓝牙适配器都有一个低功耗支持状态,它是一个布尔值,用于描述适配器 是否支持低功耗蓝牙。
一个模拟 蓝牙设备是一个软件定义的蓝牙设备,其 行为类似于物理设备,可以附加到一个模拟蓝牙 适配器, 可以具有诸如制造商特定数据和服务 UUID之类的关联属性, 并具有一个模拟 GATT 服务映射,它是一个 从蓝牙 UUID 字符串到模拟 GATT 服务的有序 映射。
一个模拟 GATT 服务是一个软件定义的服务,它属于一个 模拟蓝牙设备,具有一个 UUID 属性,在 蓝牙缓存中为已知存在,并具有一个模拟 GATT 特征映射,它 是一个从蓝牙 UUID 字符串到模拟 GATT 特征的有序映射。
一个模拟 GATT 特征是一个软件定义的特征,它属于一个 模拟 GATT 服务,具有一个 UUID 属性和一个 特征属性属性, 在蓝牙缓存中为已知存在,并具有一个模拟 GATT 描述符 映射,它 是一个从蓝牙 UUID 字符串到模拟 GATT 描述符的有序映射。
模拟 GATT 特征属性是 软件定义的特征属性,它们属于一个 模拟 GATT 特征,并在 蓝牙缓存中为已知存在。
一个模拟 GATT 描述符是一个软件定义的描述符,它属于一个 模拟 GATT 特征,具有一个 UUID 属性,并在蓝牙缓存中为已知存在。
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- 是公司标识符代码。
data- 是经过 base64 编码的制造商数据字节序列。
12.2. bluetooth 模块
bluetooth 模块包含用于管理远程端蓝牙行为的命令。
12.2.1. 类型
12.2.1.1. bluetooth.RequestDevice 类型
bluetooth.RequestDevice = text
bluetooth.RequestDevice 是请求设备提示中单个设备的标识符。
一个设备提示是一个元组,由
一个设备
提示 ID(一个字符串)和一个设备集合组成,后者是一个由 BluetoothDevice
对象组成的集合。
它表示一个允许用户选择一个蓝牙设备的提示。
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 表示蓝牙设备发送的广播数据包的数据。
name- 是蓝牙 设备的本地名称或其前缀。
uuids- 列出此扫描记录表明蓝牙设备的 GATT 服务器支持的服务 UUID。
appearance- 是一个外观值,即
gap.appearance特征定义的值之一。 manufacturerData- 一个
BluetoothManufacturerData列表,它将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, )
{ "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 的模拟 蓝牙适配器。
-
如果 simulatedBluetoothAdapter 为空,则运行以下步骤:
-
如果 params[
"leSupported"] 不存在,则将 params["leSupported"] 设置为true。 -
令 simulatedBluetoothAdapter 为一个新的模拟蓝牙适配器。
-
将 simulatedBluetoothAdapter 的LE 支持状态 设置为 params[
"leSupported"]。 -
将 navigable 的模拟蓝牙适配器设置为 simulatedBluetoothAdapter。
-
返回以
null为数据的成功。
-
-
如果 simulatedBluetoothAdapter 不为空,则运行以下步骤:
-
如果 params[
"leSupported"] 存在,则返回带有invalid argument 错误代码的错误。 -
返回以
null为数据的成功。
-
{ "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}
{ "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 的模拟 蓝牙适配器。
-
如果 simulatedBluetoothAdapter 为空,则返回带有invalid argument 错误代码的错误。
-
令 deviceAddress 为 params[
"address"]。 -
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则返回 带有invalid argument 错误 代码的错误。
-
令 simulatedBluetoothDevice 为一个新的模拟 蓝牙设备。
-
将 simulatedBluetoothDevice 的名称设置为 params[
"name"]。 -
将 simulatedBluetoothDevice 的地址设置为 params[
"address"]。 -
将 simulatedBluetoothDevice 的制造商 特定数据设置为对 params[
"manufacturerData"] 执行宽容 base64 解码的输出。 -
将 simulatedBluetoothDevice 的服务 UUID设置为 params[
"knownServiceUuids"]。 -
将 deviceMapping[deviceAddress] 设置为 simulatedBluetoothDevice。
-
返回以
null为数据的成功。
{ "method" : "bluetooth.simulatePreconnectedPeripheral" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "name" : "某个设备" , "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 的模拟蓝牙适配器。
-
如果 simulatedBluetoothAdapter 为空,则返回带有invalid argument 错误代码的错误。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。否则,令 simulatedDevice 为一个带有 deviceAddress 的新的模拟蓝牙设备,并将 deviceMapping[deviceAddress] 设置为 simulatedDevice。
-
如果 topLevelNavigable 当前正在执行扫描设备算法, 则将 simulatedDevice 插入该算法中的 simulatedBluetoothDevices 变量。
将数据 插入另一个算法的变量中并没有明确定义。扫描设备算法需要 定义异步设备发现,以便与实现相匹配。
-
令 navigables 为 topLevelNavigable 的活动文档的包含自身的后代可导航对象。
-
对于 navigables 中的每个 navigable:
-
令 document 为 navigable 的活动文档。
-
在 document 的相关设置对象的负责的事件循环上排入一个任务,以执行以下 子步骤:
-
令 simulatedDeviceInstance 为获取表示
BluetoothDevice的对象 simulatedDevice 的结果, 该对象位于 navigable 的活动窗口的关联Navigator的 关联 Bluetooth 中。 -
如果 simulatedDeviceInstance.
[[watchAdvertisementsState]]为not-watching,则中止这些子步骤。 -
在 simulatedDeviceInstance 上,针对由 scanEntry[
"scanRecord"] 表示的广播事件,触发一个advertisementreceived事件。
-
-
-
返回以
null为数据的成功。
{ "method" : "bluetooth.simulateAdvertisement" , "params" : { "context" : "cxt-d03fdd81" , "scanEntry" : { "deviceAddress" : "08:08:08:08:08:08" , "rssi" : -10 , "scanRecord" : { "name" : "心率" , "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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。 否则,返回带有无效参数错误 代码的错误。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
如果 simulatedDeviceInstance.
[[gatt]].[[automatedGATTConnectionResponse]]为"expected", 则将 simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]设置为 params["code"]。
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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。 否则,返回带有无效参数错误 代码的错误。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
如果 simulatedDeviceInstance.
[[gatt]].[[automatedGATTConnectionResponse]]为"expected", 则将 simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]设置为0x15。根据 错误代码 列表,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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 uuid 为 params[
"uuid"]。 -
-
令 simulatedGattService 为一个新的模拟 GATT 服务。
-
将 simulatedGattService 的 UUID 设置为 uuid。
-
将 serviceMapping[uuid] 设置为 simulatedGattService。
-
创建一个表示
BluetoothRemoteGATTServicesimulatedGattService 的对象,并在 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]中添加从 simulatedGattService 到所得Promise的映射。 -
返回以
null为数据的成功。
-
-
如果 serviceMapping[uuid] 存在,则令 simulatedGattService 为 serviceMapping[uuid]。
-
从 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]]中移除 simulatedGattService。 -
从 serviceMapping 中移除 uuid。
-
返回以
null为数据的成功。
-
{ "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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
如果 serviceMapping[serviceUuid] 存在,则令 simulatedService 为 serviceMapping[serviceUuid]。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征 映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
-
如果 characteristicMapping[characteristicUuid] 存在,则返回带有 无效元素状态错误代码的错误。
-
如果 params[
"characteristicProperties"] 不存在,则返回带有无效参数错误代码的错误。 -
令 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。
-
创建一个表示
BluetoothRemoteGATTCharacteristicsimulatedGattCharacteristic 的对象,并在 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]中添加从 simulatedGattCharacteristic 到所得Promise的映射。 -
返回以
null为数据的成功。
-
-
-
如果 params[
"characteristicProperties"] 存在,则返回带有无效参数错误代码的错误。 -
如果 characteristicMapping[characteristicUuid] 存在,则令 simulatedGattCharacteristic 为 characteristicMapping[characteristicUuid]。
-
从 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]]中移除 simulatedGattCharacteristic。 -
从 characteristicMapping 中移除 characteristicUuid。
-
返回以
null为数据的成功。
-
{ "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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。 否则,返回带有无效参数错误 代码的错误。
-
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
如果 serviceMapping[serviceUuid] 存在,则令 simulatedService 为 serviceMapping[serviceUuid]。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征 映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
如果 characteristicMapping[characteristicUuid] 存在,则令 simulatedGattCharacteristic 为 characteristicMapping[characteristicUuid]。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
令 promise 为 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]][simulatedGattCharacteristic]。 -
兑现后,promise 以 characteristic 兑现时,运行以下步骤:
-
如果 params[
"type"] 为"read", 则运行以下步骤:-
如果 characteristic.
[[automatedCharacteristicReadResponse]]为expected, 则将 characteristic.[[automatedCharacteristicReadResponse]]设置为 params["code"] 并将 characteristic.[[automatedCharacteristicReadResponseData]]设置为 params["data"] 所持字节的副本。
-
-
如果 params[
"type"] 为"write", 则运行以下步骤:-
如果 characteristic.
[[automatedCharacteristicWriteResponse]]为expected, 则将 characteristic.[[automatedCharacteristicWriteResponse]]设置为 params["code"]。
-
-
如果 params[
"type"] 为"subscribe-to-notifications", 则运行以下步骤:-
如果 characteristic.
[[automatedCharacteristicSubscribeToNotificationsResponse]]为expected, 则将 characteristic.[[automatedCharacteristicSubscribeToNotificationsResponse]]设置为 params["code"]。
-
-
如果 params[
"type"] 为"unsubscribe-from-notifications", 则运行以下步骤:-
如果 characteristic.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]为expected, 则将 characteristic.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]设置为 params["code"]。
-
-
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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
如果 serviceMapping[serviceUuid] 存在,则令 simulatedService 为 serviceMapping[serviceUuid]。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征 映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
如果 characteristicMapping[characteristicUuid] 存在,则令 simulatedCharacteristic 为 characteristicMapping[characteristicUuid]。
-
令 descriptorMapping 为 simulatedCharacteristic 的模拟 GATT 描述符映射。
-
令 descriptorUuid 为 params[
"descriptorUuid"]。 -
-
如果 descriptorMapping[descriptorUuid] 存在,则返回带有 无效元素状态错误代码的错误。
-
令 simulatedGattDescriptor 为一个新的模拟 GATT 描述符。
-
将 simulatedGattDescriptor 的 UUID 设置为 descriptorUuid。
-
将 descriptorMapping[descriptorUuid] 设置为 simulatedGattDescriptor。
-
创建一个表示
BluetoothRemoteGATTDescriptorsimulatedGattDescriptor 的对象,并在 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]中添加从 simulatedGattDescriptor 到所得Promise的映射。 -
返回以
null为数据的成功。
-
-
-
如果 descriptorMapping[descriptorUuid] 存在,则令 simulatedGattDescriptor 为 descriptorMapping[descriptorUuid]。
-
从 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]]中移除 simulatedGattDescriptor。 -
从 descriptorMapping 中移除 descriptorUuid。
-
返回以
null为数据的成功。
-
{ "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 的模拟 蓝牙适配器。
-
令 deviceMapping 为 simulatedBluetoothAdapter 的模拟蓝牙设备映射。
-
如果 deviceMapping[deviceAddress] 存在,则令 simulatedDevice 为 deviceMapping[deviceAddress]。 否则,返回带有无效参数错误 代码的错误。
-
令 serviceMapping 为 simulatedDevice 的模拟 GATT 服务映射。
-
令 serviceUuid 为 params[
"serviceUuid"]。 -
如果 serviceMapping[serviceUuid] 存在,则令 simulatedService 为 serviceMapping[serviceUuid]。
-
令 characteristicMapping 为 simulatedService 的模拟 GATT 特征 映射。
-
令 characteristicUuid 为 params[
"characteristicUuid"]。 -
如果 characteristicMapping[characteristicUuid] 存在,则令 simulatedCharacteristic 为 characteristicMapping[characteristicUuid]。
-
令 descriptorMapping 为 simulatedCharacteristic 的模拟 GATT 描述符映射。
-
令 descriptorUuid 为 params[
"descriptorUuid"]。 -
如果 descriptorMapping[descriptorUuid] 存在,则令 simulatedDescriptor 为 descriptorMapping[descriptorUuid]。
-
令 simulatedDeviceInstance 为在 navigable 的活动窗口的关联
Navigator的 关联 Bluetooth中获取表示BluetoothDevicesimulatedDevice 的结果。 -
令 promise 为 simulatedDeviceInstance.
[[context]].[[attributeInstanceMap]][simulatedDescriptor]。 -
兑现后,promise 以 descriptor 兑现时,运行以下步骤:
-
如果 params[
"type"] 为"read", 则运行以下步骤:-
如果 descriptor.
[[automatedDescriptorReadResponse]]为expected, 则将 descriptor.[[automatedDescriptorReadResponse]]设置为 params["code"] 并将 descriptor.[[automatedDescriptorReadResponseData]]设置为 params["data"] 所持字节的副本。
-
-
如果 params[
"type"] 为"write", 则运行以下步骤:-
如果 characteristic.
[[automatedDescriptorWriteResponse]]为expected, 则将 characteristic.[[automatedDescriptorWriteResponse]]设置为 params["code"]。
-
-
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 的可导航对象 ID。
-
令 prompt 为设备提示(promptId, devices)。
-
令 serialized devices 为使用 prompt 序列化提示 设备的结果。
-
将可导航对象到设备 提示的映射[navigableId] 设置为 prompt。
-
令 params 为一个与
bluetooth.RequestDevicePromptUpdatedParameters产生式匹配的映射,其中"context"字段设置为 navigableId,"prompt"字段设置为 promptId,并且"devices"字段设置为 serialized devices。 -
令 body 为一个与
bluetooth.RequestDevicePromptUpdated产生式匹配的映射,其中"params"字段设置为 params。 -
令 relatedNavigables 为一个包含 navigable 的集合。
-
对于给定
"bluetooth.requestDevicePromptUpdated"和 relatedNavigables 的启用了事件的会话 集合中的每个 session:-
使用 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 的可导航对象 ID。
-
令 params 为一个与
bluetooth.GattConnectionAttemptedParameters产生式匹配的映射,其中"context"字段设置为 navigableId,"address"字段设置为 device.[[representedDevice]]的 地址。 -
令 body 为一个与
bluetooth.GattConnectionAttempted产生式匹配的映射,其中"params"字段设置为 params。 -
令 relatedNavigables 为一个包含 navigable 的集合。
-
对于给定
"bluetooth.gattConnectionAttempted"和 relatedNavigables 的启用了事件的会话集合中的每个 session:-
使用 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、一个 BluetoothDevice
device、一个
模拟 GATT 特征
characteristic、一个字符串 type,以及一个可选的字节序列
bytes,要触发模拟特征事件
:
-
令 navigableId 为 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-with-response"或"write-without-response", 则运行以下步骤:
-
-
令 body 为一个与
bluetooth.CharacteristicEventGenerated产生式匹配的映射,其中"params"字段设置为 params。 -
令 relatedNavigables 为一个包含 navigable 的集合。
-
对于给定
"bluetooth.characteristicEventGenerated"和 relatedNavigables 的启用了事件的会话集合中的每个 session:-
使用 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、一个 BluetoothDevice
device、一个
模拟
GATT 描述符 descriptor、一个字符串
type,以及一个可选的字节序列
bytes,要触发模拟描述符事件 :
-
令 navigableId 为 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", 则运行以下步骤:
-
-
令 body 为一个与
bluetooth.DescriptorEventGenerated产生式匹配的映射,其中"params"字段设置为 params。 -
令 relatedNavigables 为一个包含 navigable 的集合。
-
对于给定
"bluetooth.descriptorEventGenerated"和 relatedNavigables 的启用了事件的会话集合中的每个 session:-
使用 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]
-
-
架构与术语概述
-
一般说明
- 低功耗蓝牙操作概述 (定义广播事件)
-
通信拓扑和操作
-
操作过程和模式
-
BR/EDR 过程
-
查询(发现)过程
- 扩展查询 响应
-
查询(发现)过程
-
BR/EDR 过程
-
操作过程和模式
-
一般说明
-
核心系统包 [BR/EDR 控制器卷]
-
错误代码
-
错误代码概述
- 错误代码列表
-
错误代码概述
-
主机控制器接口功能规范
-
HCI 命令和事件
-
信息参数
- 读取 BD_ADDR 命令
-
状态参数
- 读取 RSSI 命令
-
信息参数
-
HCI 命令和事件
-
错误代码
-
核心系统包 [主机卷]
-
服务发现协议(SDP)规范
-
概述
-
搜索服务
- UUID (定义UUID 别名以及 根据 UUID 别名计算所表示的 128 位 UUID 的算法)
-
搜索服务
-
概述
-
通用访问配置文件
-
配置文件概述
-
配置文件角色
-
在 LE 物理传输上运行时的角色
- 广播者 角色
- 观察者角色
- 外围设备角色
- 中心设备角色
-
在 LE 物理传输上运行时的角色
-
配置文件角色
-
用户界面方面
-
蓝牙参数的表示
- 蓝牙设备 名称(用户友好名称)
-
蓝牙参数的表示
-
空闲模式过程 — BR/EDR 物理传输
- 设备发现过程
- BR/EDR 绑定过程
-
操作模式和过程 — LE 物理传输
-
广播模式和观察过程
- 观察 过程
-
发现模式和过程
- 通用 发现过程
- 名称发现 过程
- 连接模式和过程
-
绑定模式和过程
- LE 绑定 过程
-
广播模式和观察过程
-
安全方面 — LE 物理传输
- 隐私功能
-
随机设备地址
- 静态地址
-
私有地址
- 可解析 私有地址解析过程
- 广播数据和扫描响应数据格式 (定义AD 结构)
-
蓝牙设备要求
-
蓝牙设备地址(定义BD_ADDR)
-
蓝牙设备地址类型
- 公共 蓝牙地址
-
蓝牙设备地址类型
-
蓝牙设备地址(定义BD_ADDR)
- 定义 (定义绑定)
-
配置文件概述
-
属性协议(ATT)
-
协议要求
-
基本概念
- 属性类型
- 属性句柄
- 长属性 值
-
属性协议 PDU
-
错误处理
- 错误 响应
-
错误处理
-
基本概念
-
协议要求
-
通用属性配置文件(GATT)
-
配置文件概述
- 配置和角色 (定义GATT 客户端和GATT 服务器)
- 配置文件基础, 定义ATT 承载
-
属性协议
- 属性缓存
-
GATT 配置文件层次结构
- 服务
- 包含服务
- 特征
-
服务互操作性
要求
- 服务定义
-
特征定义
-
特征声明
- 特征 属性
-
特征描述符声明
- 特征 扩展属性
- 客户端 特征配置
-
特征声明
-
GATT 功能要求 — 定义
GATT 过程。
-
服务器配置
- 交换 MTU
-
主服务发现
- 发现所有主服务
- 按服务 UUID 发现 主服务
-
关系发现
- 查找包含服务
-
特征发现
- 发现服务的所有特征
- 按 UUID 发现 特征
-
特征描述符
发现
- 发现所有 特征描述符
- 特征值读取
-
特征值写入
- 无响应 写入
- 写入 特征值
- 特征值 通知
- 特征值 指示
-
特征描述符
- 读取 特征描述符
- 读取 长特征描述符
- 写入 特征描述符
- 写入长 特征描述符
- 过程超时
-
服务器配置
-
GAP 互操作性
要求
-
BR/EDR GAP 互操作性要求
- 连接建立
-
LE GAP 互操作性要求
- 连接建立
-
BR/EDR GAP 互操作性要求
-
已定义的通用属性配置文件服务
- 服务已更改
-
配置文件概述
-
安全管理器规范
-
安全管理器
-
低功耗蓝牙中的安全
- 密钥 和值的定义, 定义 身份解析密钥 (IRK)
-
低功耗蓝牙中的安全
-
安全管理器
-
服务发现协议(SDP)规范
-
核心系统包 [低功耗控制器卷]
-
链路层规范
-
一般说明
-
设备地址
- 公共设备 地址
-
随机设备地址
- 静态 设备地址
-
设备地址
-
空中接口协议
-
非连接状态
-
扫描状态
- 被动 扫描
-
扫描状态
-
非连接状态
-
一般说明
-
链路层规范
-
架构与术语概述
- [BLUETOOTH-SUPPLEMENT6]
-
-
数据类型规范
-
数据类型定义和格式
- 服务 UUID 数据类型
- 本地名称数据类型
- 标志数据类型 (定义可发现模式标志)
- 制造商特定数据
- TX 功率级别
- 服务数据
- 外观
-
数据类型定义和格式
-
数据类型规范