웹 블루투스

커뮤니티 그룹 초안 보고서,

이 문서에 대한 자세한 정보
현재 버전:
https://webbluetoothcg.github.io/web-bluetooth/
이슈 추적:
GitHub
명세 내 인라인
편집자:
(Google LLC)
(Google LLC)
GitHub에서 기여자 보기
번역 (비공식):
日本語
참여하기:
W3C 커뮤니티 그룹 참여
GitHub에서 텍스트 수정
public-web-bluetooth@w3.org (아카이브)
IRC: W3C의 #web-bluetooth

요약

이 문서는 일반 특성 프로파일(GATT)을 사용하여 Bluetooth 4 무선 표준을 통해 장치를 검색하고 통신하는 API를 설명합니다.

이 문서의 현황

이 명세는 Web Bluetooth 커뮤니티 그룹에서 발행했습니다. 이는 W3C 표준이 아니며 W3C 표준 트랙에 있지 않습니다. W3C 커뮤니티 기여자 라이선스 계약(CLA) 하에서 제한적인 옵트아웃이 가능하며, 기타 조건이 적용됩니다. W3C 커뮤니티 및 비즈니스 그룹에 대해 더 알아보세요.

이 문서의 변경 사항은 https://github.com/WebBluetoothCG/web-bluetooth/commits/gh-pages에서 추적할 수 있습니다.

이 문서에 대한 의견을 남기고 싶으신 경우, public-web-bluetooth@w3.org로 보내주시기 바랍니다 (구독, 아카이브).

1. 소개

이 절은 비규범적입니다.

Bluetooth는 장치 간 단거리 무선 통신을 위한 표준입니다. Bluetooth "Classic"(BR/EDR) 는 이진 프로토콜 집합을 정의하며 약 24Mbps까지의 속도를 지원합니다. Bluetooth 4.0은 "Bluetooth Smart" 또는 BLE, 또는 간단히 LE로 알려진 새로운 "저전력" 모드를 도입했으며, 이는 약 1Mbps로 제한되지만 기기가 대부분의 시간 동안 송신기를 꺼둘 수 있게 합니다. BLE는 Generic Attribute Profile (GATT)에서 제공하는 key/value 쌍을 통해 대부분의 기능을 제공합니다.

BLE는 장치가 수행할 수 있는 여러 역할을 정의합니다. BroadcasterObserver 역할은 각각 송신 전용, 수신 전용 애플리케이션을 위한 역할입니다. Peripheral 역할의 장치는 연결을 받을 수 있고, Central 역할의 장치는 Peripheral 장치에 연결할 수 있습니다.

Peripheral 또는 Central 역할을 하는 장치는 GATT Server를 호스팅할 수 있으며, 이 서버는 Service, Characteristic, Descriptor의 계층 구조를 노출합니다. 이 계층 구조에 대한 자세한 내용은 § 6.1 GATT 정보 모델을 참고하십시오. GATT 프로토콜은 BLE 전송을 지원하도록 설계되었지만, BR/EDR 전송에서도 실행될 수 있습니다.

이 명세의 첫 번째 버전에서는 UA에서 Central 역할로 동작하는 웹페이지가 BR/EDR 또는 LE 연결을 통해 GATT Server에 연결할 수 있습니다. 본 명세는 [BLUETOOTH42] 명세를 인용하지만, Bluetooth 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 를 읽어 BluetoothRemoteGATTCharacteristicvalue 필드를 해석하는 식으로 정의할 수 있습니다.

function parseHeartRate(data) {
  const flags = data.getUint8(0);
  const rate16Bits = flags & 0x1;
  const result = {};
  let index = 1;
  if (rate16Bits) {
    result.heartRate = data.getUint16(index, /*littleEndian=*/true);
    index += 2;
  } else { 
    result.heartRate = data.getUint8(index);
    index += 1;
  }
  const contactDetected = flags & 0x2;
  const contactSensorPresent = flags & 0x4;
  if (contactSensorPresent) {
    result.contactDetected = !!contactDetected;
  }
  const energyPresent = flags & 0x8;
  if (energyPresent) {
    result.energyExpended = data.getUint16(index, /*littleEndian=*/true);
    index += 2;
  }
  const rrIntervalPresent = flags & 0x10;
  if (rrIntervalPresent) {
    const rrIntervals = [];
    for (; index + 1 < data.byteLength; index += 2) {
      rrIntervals.push(data.getUint16(index, /*littleEndian=*/true));
    }
    result.rrIntervals = rrIntervals;
  }
  return result;
}

onHeartRateChanged() 함수는 다음과 같은 객체를 출력할 수 있습니다.

{
  heartRate: 70,
  contactDetected: true,
  energyExpended: 750,     // 750kJ을 의미합니다.
  rrIntervals: [890, 870]  // 각각 0.87초, 0.85초를 의미합니다.
}

심박 센서가 energyExpended 필드를 보고하는 경우, 웹 애플리케이션은 0을 해당 값으로 리셋할 수 있으며 다음과 같이 heart_rate_control_point 특성에 값을 쓸 수 있습니다:

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 개인정보 보호 고려사항 섹션 참고. [이슈 #575]

3. 개인정보 보호 고려사항

3.1. 장치 접근은 강력합니다

웹사이트가 requestDevice()를 사용하여 장치 접근을 요청하면, 호출에 명시된 모든 GATT 서비스에 접근할 수 있는 권한을 얻게 됩니다. UA는 해당 서비스들이 웹사이트에 어떠한 권한을 부여하는지 사용자에게 알려주어야 하며, 어떤 장치를 신뢰할지 물어보아야 합니다. 만약 목록에 있는 서비스 중 UA에서 알려지지 않은 서비스가 있다면, UA는 해당 서비스가 사이트에 장치의 완전한 제어 권한을 제공한다고 가정하고 이 위험성을 사용자에게 알려주어야 합니다. 또한 UA는 사용자가 어떤 사이트가 어떤 장치에 접근 권한을 가지고 있는지 확인하고, 이러한 페어링을 철회할 수 있도록 해야 합니다.

UA는 사용자가 전체 장치 클래스를 웹사이트와 페어링하는 것을 허용해서는 안 됩니다. 동일한 Bluetooth 수준의 식별 정보를 보내는 장치 클래스를 조작하는 것도 가능합니다. UA는 이러한 위조를 감지할 필요는 없으며, 사용자가 이러한 가짜 장치를 웹사이트와 페어링하도록 허용할 수 있습니다.

사용자가 접근을 허락한 주체만 진짜로 접근하도록 보장하기 위해, 이 명세는 보안 컨텍스트에서만 Bluetooth 장치에 접근할 수 있도록 요구합니다.

3.2. 신뢰된 서버도 악성 코드를 제공할 수 있음

이 절은 비규범적입니다.

사용자가 어떤 오리진을 신뢰하더라도, 그 오리진의 서버나 개발자가 훼손될 수 있고, 사이트가 XSS 공격에 취약할 수도 있습니다. 이로 인해 사용자가 악성 코드에 귀중한 장치 접근 권한을 부여할 수도 있습니다. 오리진은 Content Security Policy([CSP3])를 정의하여 XSS 공격 위험을 줄일 수 있지만, 서버 또는 개발자 자체가 훼손된 경우에는 도움이 되지 않습니다.

§ 4.1 Permission API 통합에서 제공하는, 페이지 리로드 후에도 허가된 장치를 다시 가져올 수 있는 능력은 이러한 위험을 더 악화시킵니다. 사이트가 훼손된 동안에만 사용자의 접근 권한을 새로 받아낼 필요 없이, 사용자가 단순히 방문만 하더라도 기존에 허가된 장치를 악용할 수 있기 때문입니다. 반면, 사이트가 페이지 리로드가 되어도 장치 접근을 유지할 수 있다면 전체적으로 권한 요청 프롬프트를 더 적게 보여줄 수 있어서, 사용자가 실제로 보는 프롬프트에 더 주의를 기울일 수 있습니다.

3.3. 장치에 대한 공격

이 절은 비규범적입니다.

웹사이트의 통신은 일부 장치의 보안 모델을 깨뜨릴 수 있습니다. 이들 장치는 원격 장치의 신뢰할 수 있는 운영체제로부터만 메시지를 받을 것으로 가정합니다. 인간-인터페이스 장치(HID)가 대표적인 예이며, 웹사이트가 통신할 수 있게 되면 해당 사이트가 키 입력을 기록할 수도 있습니다. 본 명세는 이러한 취약한 서비스, 특성 및 디스크립터를 웹사이트에서 악용하지 못하게 GATT 차단 목록을 포함합니다.

많은 장치가 무선으로 전달되는 예기치 않은 데이터에 취약할 것이라 예상합니다. 이전에는 이러한 장치를 하나씩 직접 공격해야 했지만, 이 API를 통해 대규모 공격도 가능하게 됩니다. 본 명세는 이러한 공격을 어렵게 만들기 위해 여러 접근법을 사용합니다:

UA는 사용자를 보호하기 위해 추가적인 조치를 취할 수도 있습니다:

3.4. 블루투스 장치 식별자

이 절은 비규범적입니다.

각 Bluetooth BR/EDR 장치는 BD_ADDR로 알려진 고유한 48비트 MAC 주소를 가집니다. 각 Bluetooth LE 장치는 공개 장치 주소정적 장치 주소 중 하나 이상을 가질 수 있습니다. 공개 장치 주소 는 MAC 주소입니다. 정적 장치 주소는 장치가 재시작될 때마다 재생성될 수 있습니다. BR/EDR/LE 장치는 BD_ADDR공개 장치 주소에 동일한 값을 사용할 수 있습니다(이는 Read BD_ADDR Command에 명시되어 있습니다).

LE 장치는 고유한 128비트 Identity Resolving Key도 가질 수 있으며, 이 값은 본딩 도중 신뢰된 장치에 전송됩니다. 영구 식별자 정보를 누출하지 않기 위해, LE 장치는 정적/공개 주소 대신 임의의 Resolvable 또는 Non-Resolvable 개인 주소를 사용하여 스캔 및 광고를 할 수 있습니다. 이 값들은 주기적으로(약 15분마다) 재생성되지만, 본딩된 장치는 저장된 IRK를 사용하여 전송된 Resolvable Private Address가 자신과 매칭되는지 Resolvable Private Address Resolution Procedure로 확인할 수 있습니다.

각 Bluetooth 장치는 또한 사람이 읽을 수 있는 Bluetooth 장치 이름을 가집니다. 이 값은 고유성이 보장되지 않지만, 장치 유형에 따라 고유할 수 있습니다.

3.4.1. 원격 블루투스 장치 식별자

이 절은 비규범적입니다.

웹사이트가 영구적인 장치 ID 중 하나라도 가져올 수 있으면, 주변 장치를 대규모로 카탈로그하는 노력을 통해 사용자의 위치를 확인하는 데 악용될 수 있습니다. 장치 ID는 사용자가 동일한 블루투스 장치로 두 개의 다른 웹사이트와 페어링할 때도 한 명의 사용자임을 식별하는 데 사용할 수 있습니다. 반면 많은 GATT 서비스는 장치의 지문을 채취하는 데 활용될 수 있고, 장치는 맞춤형 GATT 서비스를 노출하여 이를 더 쉽게 만들 수도 있습니다.

본 명세서는 권고를 통해 UA가 단일 장치에 대해 사용자가 단일 장치임을 스크립트가 알기를 원하지 않을 경우 서로 다른 장치 ID를 사용하도록 제안합니다. 이로써 웹사이트에서 장치 주소를 악용하기 어렵게 만들 수 있습니다. 물론, 장치 제조사는 여전히 사용자를 추적하도록 설계할 수 있지만, 이는 추가적인 노력이 필요합니다.

3.4.2. UA의 블루투스 주소

이 절은 비규범적입니다.

BR/EDR 모드 또는 Privacy Feature가 활성화되지 않은 LE 모드의 액티브 스캐닝 중에는, UA는 어떤 인근 Bluetooth 라디오에도 자신의 영구 ID를 브로드캐스트합니다. 이는 특정 구역에 악성 장치를 배치해 UA를 추적하기 쉽게 만듭니다. 2014년 8월 기준, Privacy Feature를 구현한 플랫폼은 거의 없거나 전혀 없으며, 이 스펙에서 이를 권장함에도 불구하고 실제로 UA들이 사용할 가능성은 높지 않습니다. 본 스펙은 사용자 동작을 통해서만 스캔을 트리거할 수 있도록 요구하여 스캔 빈도를 어느 정도 낮춥니다. 하지만 여전히 더 많은 플랫폼이 Privacy Feature를 노출하는 것이 더 좋을 것입니다.

3.5. 블루투스 사용 가능성 노출

이 절은 비규범적입니다.

navigator.bluetooth.getAvailability() 는 사용자의 시스템에 블루투스 라디오가 존재하는지(전원이 켜져 있는지와 관계없이) 노출합니다. 웹 블루투스 접근이 UA에서 차단된 경우에도 사용 가능성은 달라집니다. 일부 사용자는 이 정보도 프라이빗하다고 여길 수 있으나, 이를 공개해서 생기는 피해는 상상하기 힘듭니다. 이 정보는 또한 UA의 지문 표면을 일부 넓힙니다. 이 함수는 Promise를 반환하여, UA가 사용자가 어떤 값을 반환할지 물어보는 것이 가능하지만, 위험이 충분히 낮아 실제로 프롬프트를 띄우지 않을 것으로 예상합니다.

4. 장치 검색

dictionary BluetoothDataFilterInit {
  BufferSource dataPrefix;
  BufferSource mask;
};

dictionary BluetoothManufacturerDataFilterInit : BluetoothDataFilterInit {
  required [EnforceRange] unsigned short companyIdentifier;
};

dictionary BluetoothServiceDataFilterInit : BluetoothDataFilterInit {
  required BluetoothServiceUUID service;
};

dictionary BluetoothLEScanFilterInit {
  sequence<BluetoothServiceUUID> services;
  DOMString name;
  DOMString namePrefix;
  sequence<BluetoothManufacturerDataFilterInit> manufacturerData;
  sequence<BluetoothServiceDataFilterInit> serviceData;
};

dictionary RequestDeviceOptions {
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothLEScanFilterInit> exclusionFilters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};

[Exposed=Window, SecureContext]
interface Bluetooth : EventTarget {
  Promise<boolean> getAvailability();
  attribute EventHandler onavailabilitychanged;
  [SameObject]
  readonly attribute BluetoothDevice? referringDevice;
  Promise<sequence<BluetoothDevice>> getDevices();
  Promise<BluetoothDevice> requestDevice(optional RequestDeviceOptions options = {});
};

Bluetooth includes BluetoothDeviceEventHandlers;
Bluetooth includes CharacteristicEventHandlers;
Bluetooth includes ServiceEventHandlers;

이 명세에서 정의된 메서드는 일반적으로 비동기적으로 완료되며, Bluetooth 작업 소스에 작업을 대기시킵니다.

참고: Bluetooth 멤버
참고: getAvailability() 는 페이지에 Bluetooth가 전반적으로 사용 가능한지 여부를 알려줍니다. 소프트웨어로 비활성화된 어댑터도 사용 가능한 것으로 간주되어야 합니다. 사용자가 물리적으로 어댑터를 연결하거나 분리하는 등의 사용 가능성 변경은 availabilitychanged 이벤트를 통해 보고됩니다.

referringDevice 는 사용자가(있다면) 이 페이지를 연 장치에 대한 접근을 제공합니다. 예를 들어 Eddystone 비콘이 URL을 광고할 수 있고, UA가 사용자가 그 URL을 열도록 허용할 수 있습니다. 해당 비콘을 나타내는 BluetoothDevicenavigator.bluetooth.referringDevice 를 통해 제공됩니다.

getDevices() 는 사용자가 접근을 허가한 Bluetooth 장치를 페이지가 조회할 수 있도록 합니다.

requestDevice(options) 는 이 오리진이 options.filters 에 있는 아무 필터와도 일치하지만 options.exclusionFilters 에 있는 어떤 필터와도 일치하지 않는 장치에 대한 접근을 사용자에게 요청합니다. 필터와 일치하려면, 장치는 다음을 만족해야 합니다:

제조사별 데이터서비스 데이터는 키를 바이트 배열에 매핑합니다. BluetoothDataFilterInit 는 이 배열을 필터링합니다. 배열은 어떤 prefix 가 존재하여 prefix & mask 가 다음과 같을 때 일치합니다: dataPrefix & mask.

장치가 연결 시 동작이 크게 바뀌는 경우(예: 더 이상 식별용 제조사 데이터를 광고하지 않고, 대신 클라이언트가 식별 가능한 GATT 서비스를 발견하게 하는 경우), 웹사이트는 두 동작 모두에 대한 필터를 포함해야 할 수도 있습니다.

드문 경우, 장치가 사이트가 관심 없는 장치를 걸러낼 만큼 충분한 구분 정보를 광고하지 않을 수 있습니다. 이런 경우 사이트는 acceptAllDevicestrue 로 설정하고 모든 filtersexclusionFilters 를 생략할 수 있습니다. 이 경우 올바른 장치를 선택하는 책임은 전적으로 사이트 사용자에게 있습니다. 사이트가 acceptAllDevices 를 사용하면, optionalServices 에 나열된 서비스만 사용할 수 있습니다.

사용자가 이 오리진과 페어링할 장치를 선택한 후, 오리진은 services 목록에 나열된 UUID의 서비스를 options.filters 의 어떤 요소에서든, 또는 options.optionalServices 에서든 접근할 수 있습니다. 또한 오리진은 장치의 광고 데이터에 포함된 options.optionalManufacturerData 에 정의된 제조사 코드의 제조사 데이터를 접근할 수 있습니다.

이는 개발자가 이름으로만 필터링하는 경우, 어떤 서비스에도 접근하려면 optionalServices 를 사용해야 함을 의미합니다.

UA가 다음 장치들에 가까이 있다고 가정해봅시다:
Device Advertised Services
D1 A, B, C, D
D2 A, B, E
D3 C, D
D4 E
D5 <none>

웹사이트가 다음을 호출하면

navigator.bluetooth.requestDevice({
  filters: [ {services: [A, B]} ]
});

사용자에게 D1과 D2가 포함된 대화상자가 표시됩니다. 사용자가 D1을 선택하면, 웹사이트는 서비스 C 또는 D에 접근할 수 없습니다. 사용자가 D2를 선택하면, 웹사이트는 서비스 E에 접근할 수 없습니다.

반면, 웹사이트가 다음을 호출하면

navigator.bluetooth.requestDevice({
  filters: [
    {services: [A, B]},
    {services: [C, D]}
  ]
});

대화상자에는 D1, D2, D3가 포함되며, 사용자가 D1을 선택하면 웹사이트는 서비스 A, B, C, D에 모두 접근할 수 있습니다.

그 후 웹사이트가

navigator.bluetooth.getDevices();

를 호출하면, 반환되는 Promise 는 D1을 포함하는 배열로 이행되며, 웹사이트는 서비스 A, B, C, D에 접근할 수 있습니다.

optionalServices 목록은 사용자가 보는 대화상자에 장치를 추가하지는 않지만, 사용자가 선택한 장치에서 웹사이트가 사용할 수 있는 서비스에 영향을 줍니다.

navigator.bluetooth.requestDevice({
  filters: [ {services: [A, B]} ],
  optionalServices: [E]
});

D4에는 필수 서비스가 없으므로 D1과 D2가 포함된 대화상자가 표시됩니다. 사용자가 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에 접근할 수 있습니다.

이전 예의 장치들이 다음과 같이 이름도 광고한다고 가정해봅시다:
Device Advertised Device Name
D1 First De…
D2 <none>
D3 Device Third
D4 Device Fourth
D5 Unique Name

다음 표는 navigator.bluetooth.requestDevice({filters: filters}) 에 전달된 filters 의 여러 값에 대해 사용자가 선택할 수 있는 장치가 무엇인지 보여줍니다.

filters Devices Notes
[{name: "Unique Name"}]
D5
[{namePrefix: "Device"}]
D3, D4
[{name: "First De"},
  {name: "First Device"}]
<none> D1은 이름의 접두사만 광고하므로 전체 이름과 일치시키려는 시도는 실패합니다.
[{namePrefix: "First"},
  {name: "Unique Name"}]
D1, D5
[{services: [C],
  namePrefix: "Device"},
  {name: "Unique Name"}]
D3, D5

다음 표는 navigator.bluetooth.requestDevice({filters: filters, exclusionFilters: exclusionFilters}) 에 전달된 filtersexclusionFilters 의 여러 값에 대해 사용자가 선택할 수 있는 장치가 무엇인지 보여줍니다.

filters exclusionFilters Devices
[{namePrefix: "Device"}]  // D3, D4
[{name: "Device Third"}]   // D3
D4
[{namePrefix: "Device"}]  // D3, D4
[{namePrefix: "Device F"}] // D4
D3
[{services: [C]},         // D1, D3
  {namePrefix: "Device"}] // D3, D4
[{services: [A]},          // D1
  {name: "Device Fourth"}] // D4
D3
이전 예의 장치들이 다음과 같이 제조사 또는 서비스 데이터도 광고한다고 가정해봅시다:
Device Manufacturer Data Service Data
D1 17: 01 02 03
D2 A: 01 02 03

다음 표는 navigator.bluetooth.requestDevice({filters: filters}) 에 전달된 filters 의 여러 값에 대해 사용자가 선택할 수 있는 장치가 무엇인지 보여줍니다.

filters Devices
[{ manufacturerData: [{ companyIdentifier: 17 }] }]
D1
[{ serviceData: [{ service: "A" }] }]
D2
[
  { manufacturerData: [{ companyIdentifier: 17 }] },
  { serviceData: [{ service: "A" }] },
]
D1, D2
[
  {
    manufacturerData: [{ companyIdentifier: 17 }],
    serviceData: [{ service: "A" }],
  },
]
<none>
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([1, 2, 3])
      },
    ],
  },
]
D1
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([1, 2, 3, 4])
      },
    ],
  },
]
<none>
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([1])
      },
    ],
  },
]
D1
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([0x91, 0xAA]),
        mask: new Uint8Array([0x0f, 0x57]),
      },
    ],
  },
]
D1
[
  {
    manufacturerData: [
      { companyIdentifier: 17 },
      { companyIdentifier: 18 },
    ]
  }
]
<none>
가능한 모든 장치를 수락하거나 거부하는 필터는 TypeError 를 유발합니다. 모든 장치를 수락하려면 대신 acceptAllDevices 를 사용하십시오.
Call Notes
requestDevice({})
잘못됨: 필터 목록이 없으면 어떤 장치도 수락하지 않습니다.
requestDevice({filters:[]})
잘못됨: 빈 필터 목록은 어떤 장치도 수락하지 않습니다.
requestDevice({filters:[{}]})
잘못됨: 비어 있는 필터는 모든 장치를 수락하므로 허용되지 않습니다.
requestDevice({
  acceptAllDevices:true
})
올바름: acceptAllDevices 로 모든 장치를 명시적으로 수락합니다.
requestDevice({
  filters: [...],
  acceptAllDevices:true
})
잘못됨: acceptAllDevices 가 어떤 filters 도 무시하게 됩니다.
requestDevice({
  exclusionFilters: [...],
  acceptAllDevices:true
})
잘못됨: acceptAllDevices 가 어떤 exclusionFilters 도 무시하게 됩니다.
requestDevice({
  exclusionFilters: [...]
})
잘못됨: exclusionFilters 를 사용하려면 filters 가 필요합니다.
requestDevice({
  filters: [...],
  exclusionFilters: []
})
잘못됨: 장치를 제외하려면 exclusionFilters 가 비어 있지 않아야 합니다.
requestDevice({
  filters: [{namePrefix: ""}]
})
잘못됨: namePrefix 가 존재한다면, 장치를 필터링하려면 비어 있지 않아야 합니다.
requestDevice({
  filters: [{manufacturerData: []}]
})
잘못됨: manufacturerData 가 존재한다면, 장치를 필터링하려면 비어 있지 않아야 합니다.
requestDevice({
  filters: [{serviceData: []}]
})
잘못됨: serviceData 가 존재한다면, 장치를 필터링하려면 비어 있지 않아야 합니다.

Bluetooth 의 인스턴스는 다음 표에 설명된 내부 슬롯과 함께 생성됩니다:

Internal Slot Initial Value Description (non-normative)
[[deviceInstanceMap]] Bluetooth device 에서 BluetoothDevice 인스턴스로의 비어 있는 맵. 단일 전역 객체 내에서 각 Bluetooth device 를 오직 하나의 BluetoothDevice 인스턴스가 나타내도록 보장합니다.
[[attributeInstanceMap]] Bluetooth cache 항목에서 Promise 로의 비어 있는 맵. 해당 Promise 들은 BluetoothRemoteGATTService, BluetoothRemoteGATTCharacteristic, 또는 BluetoothRemoteGATTDescriptor 인스턴스로 이행됩니다.
[[referringDevice]] null Document 가 장치에서 열렸다면, Document 객체 초기화 중에 BluetoothDevice 로 설정됩니다.
navigator.bluetooth.referringDevice 를 가져오면 [[referringDevice]] 를 반환해야 합니다.
일부 UA는 사용자가 탐색 컨텍스트탐색 하도록 Bluetooth device 에 응답해 허용할 수 있습니다.
참고: 예를 들어, Eddystone 비콘이 URL을 광고하면, UA는 사용자가 해당 URL로 이동하도록 허용할 수 있습니다.

이런 일이 발생하면, Document 객체 초기화 의 일부로서, UA는 다음 단계를 수행해야 합니다:

  1. referringDevice 를 탐색을 유발한 장치로 둡니다.

  2. 대표하는 BluetoothDevice 가져오기 를 통해 navigator.bluetooth 내에서 referringDevice 를 나타내는 객체를 얻고, 그 결과를 referringDeviceObj 로 둡니다.

  3. 이전 단계에서 예외가 발생했다면, 이 단계를 중단합니다.

    참고: 이는 UA가 사용자가 현재 realmreferringDevice 에 대한 접근을 허용하려 했다고 추론하지 않았음을 의미합니다. 예를 들어, 사용자가 전역적으로 GATT 접근을 거부했을 수 있습니다.
  4. navigator.bluetooth.[[referringDevice]]referringDeviceObj 로 설정합니다.

Bluetooth device device 는, 다음 단계가 match 를 반환한다면 필터와 일치 하는 것입니다. 대상 필터는 filter 입니다.
  1. filter.name 이 존재한다면, deviceBluetooth Device Name 이 완전하고 filter.name 과 동일하지 않다면 mismatch 를 반환합니다.

  2. filter.namePrefix 가 존재한다면, deviceBluetooth Device Name 이 존재하지 않거나 filter.namePrefix 로 시작하지 않으면 mismatch 를 반환합니다.

  3. filter.services 의 각 uuid 에 대해, UA가 광고 데이터, 확장 조회 응답, 또는 장치가 UUID uuid 를 가진 기본(포함된 것이 아닌) 서비스를 지원함을 나타내는 서비스 검색 응답을 받지 않았다면 mismatch 를 반환합니다.

  4. filter["manufacturerData"] 의 각 manufacturerData 에 대해, device제조사별 데이터 를 광고하지 않았거나 회사 식별자 코드가 manufacturerData["companyIdentifier"] 와 같지 않거나, 데이터가 일치 하지 않으면 mismatch 를 반환합니다.

  5. filter["serviceData"] 의 각 serviceData 에 대해, device 가 128비트 형태가 serviceData["service"] 인 UUID의 서비스 데이터 를 광고하지 않았거나, 데이터가 일치 하지 않으면 mismatch 를 반환합니다.

  6. match 를 반환합니다.

바이트 배열 data 가 다음 단계가 match 를 반환할 때, BluetoothDataFilterInit filter일치 합니다.
참고: 이 알고리즘은 filter 가 이미 정규화 되었음을 가정합니다.
  1. expectedPrefixfilter.dataPrefix 가 보유한 바이트의 사본 으로 둡니다.

  2. maskfilter.mask 가 보유한 바이트의 사본 으로 둡니다.

  3. data 의 바이트 수가 expectedPrefix 보다 적으면 mismatch 를 반환합니다.

  4. mask 의 각 1 비트에 대해, data 의 해당 비트가 expectedPrefix 의 해당 비트와 다르면 mismatch 를 반환합니다.

  5. match 를 반환합니다.

BluetoothDataFilterInit filter1 이 다음 단계가 true 를 반환할 때, 엄격한 부분집합 이며, 비교 대상은 BluetoothDataFilterInit filter2 입니다:
  1. filter1 의 길이가 filter2 의 길이보다 짧으면 false 를 반환합니다.

  2. byteIndex0 으로 둡니다.

  3. byteIndexfilter2 의 길이보다 작은 동안 다음 하위 단계를 수행합니다:

    1. filter1.mask[byteIndex] & filter2.mask[byteIndex]filter2.mask[byteIndex] 와 같지 않으면 false 를 반환합니다.

    2. filter1.dataPrefix[byteIndex] & filter2.mask[byteIndex]filter2.dataPrefix[byteIndex] & filter2.mask[byteIndex] 와 같지 않으면 false 를 반환합니다.

    3. byteIndexbyteIndex + 1 로 설정합니다.

  4. true 를 반환합니다.

장치가 광고하는 서비스 UUID 목록에는 장치가 지원하는 모든 UUID가 포함되지 않을 수 있습니다. 광고 데이터는 이 목록이 완전한지 여부를 지정합니다. 웹사이트가 근처 장치가 지원하지만 광고하지는 않는 UUID로 필터링하면, 해당 장치는 사용자에게 표시되는 장치 목록에 포함되지 않을 수 있습니다. UA가 장치에 연결해 지원 서비스의 전체 목록을 발견해야 하는데, 이는 무선 성능을 저하시킬 수 있고 지연을 유발할 수 있으므로, 이 명세는 이를 요구하지 않습니다.
getDevices() 메서드는, 호출되어 BluetoothPermissionStorage storage 가 주어졌을 때 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. global연결된 Document 가 "bluetooth" 라는 정책 제어 기능사용할 수 없음 이라면, 거부된 프라미스SecurityError 로 반환합니다.

  3. promise새로운 프라미스 로 둡니다.

  4. 다음 단계를 병렬로 실행합니다:

    1. devices 를 새 비어 있는 Array 로 둡니다.

    2. storage.allowedDevices 의 각 allowedDevice 에 대해, allowedDevice@[[device]] 를 나타내는 BluetoothDevice 객체를 devices 에 추가합니다.

    3. 전역 작업 대기Bluetooth 작업 소스 에, global 을 주어 resolve 하여 promisedevices 로 이행하도록 합니다.

    참고: devices 내의 BluetoothDevice 들은 Bluetooth 라디오의 범위 내에 없을 수도 있습니다. devices 의 특정 device 에 대해서는, watchAdvertisements() 메서드를 사용해 device 가 범위 내에 있고 광고 패킷을 브로드캐스트하는 시점을 관찰할 수 있습니다. deviceadvertisementreceived 이벤트 event 가 발생하면, event.device.gatt.connect() 호출로 연결을 설정할 수 있을 정도로 충분히 가까움을 나타낼 수 있습니다.
  5. promise 를 반환합니다.

requestDevice(options) 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. options.exclusionFilters 가 존재하고 options.filters 가 존재하지 않으면, 거부된 프라미스TypeError 로 반환합니다.

  2. options.filters 가 존재하면서 options.acceptAllDevicestrue 인 경우, 또는 options.filters 가 없고 options.acceptAllDevicesfalse 인 경우, 거부된 프라미스TypeError 로 반환합니다.

    참고: 이는 filtersacceptAllDevices:true 중 정확히 하나만 존재하도록 강제합니다.
  3. promise새로운 프라미스 로 둡니다.

  4. 다음 단계를 병렬로 실행합니다:

    1. Bluetooth 장치 요청 을 수행합니다. 이때 options.filtersoptions.acceptAllDevicesfalse 일 때 전달하고, 그렇지 않으면 null 을 전달합니다. 또한 options.exclusionFilters 가 존재하면 전달하고, 그렇지 않으면 null 을 전달합니다. 그리고 options.optionalServicesoptions.optionalManufacturerData 도 전달합니다. 결과를 devices 로 둡니다.

    2. 전역 작업 대기Bluetooth 작업 소스 에, this관련 전역 객체 를 주어 다음 단계를 실행합니다:

      1. 이전 단계에서 예외가 발생했다면, 그 예외로 promise 를 거부하고 이 단계를 중단합니다.

      2. devices 가 빈 시퀀스라면, NotFoundErrorpromise 를 거부하고 이 단계를 중단합니다.

      3. promise 를 이행 하되, devices[0] 으로 이행합니다.

  5. promise 를 반환합니다.

Bluetooth 장치 요청 을 수행하기 위해, 주어진 BluetoothPermissionStorage storage 와, BluetoothLEScanFilterInit 의 시퀀스인 filters (모든 장치가 일치할 수 있음을 나타내기 위해 null 일 수 있음), BluetoothLEScanFilterInit 의 시퀀스인 exclusionFilters (제외 필터가 설정되지 않은 경우 null 일 수 있음), BluetoothServiceUUID 의 시퀀스인 optionalServices, 그리고 unsigned short 의 시퀀스인 optionalManufacturerData 가 주어졌을 때, UA는 다음 단계를 수행해야 합니다:
참고: 이 단계들은 블록될 수 있으므로, 이 알고리즘의 사용은 병렬로 수행되어야 합니다.
참고: 이 알고리즘은 결국 여러 장치를 요청할 수 있게 되겠지만, 현재는 항상 단 하나만 반환합니다.
  1. globalstorage관련 전역 객체 로 둡니다.

  2. documentglobal연결된 Document 로 둡니다.

  3. document 가 "bluetooth" 라는 정책 제어 기능사용할 수 없음 이라면 SecurityError 를 던지고 단계를 중단합니다.

  4. 이 알고리즘이 트리거될 때 관련 전역 객체일시적 활성화 를 보유하고 있는지 확인하고, 그렇지 않다면 SecurityError 를 던지며 단계를 중단합니다.

  5. 서비스 이름과 별칭에서 UUID 로 인자를 변환하기 위해 다음 하위 단계를 수행합니다:

    1. filters !== null && filters.length === 0 이면 TypeError 를 던지고 단계를 중단합니다.

    2. exclusionFilters !== null && exclusionFilters.length === 0 이면 TypeError 를 던지고 단계를 중단합니다.

    3. uuidFilters 를 새 Array 로, uuidExclusionFilters 를 새 Array 로, requiredServiceUUIDs 를 새 Set 으로 둡니다.

    4. filtersnull 이면, requiredServiceUUIDs 를 모든 UUID의 집합으로 설정합니다.

    5. filtersnull 이 아니면, 각 filter 에 대해 다음을 수행합니다:

      1. canonicalFilter정규화 한 결과로 둡니다.

      2. canonicalFilteruuidFilters 에 추가합니다.

      3. canonicalFilter.services 의 내용을 requiredServiceUUIDs 에 추가합니다.

    6. exclusionFiltersnull 이 아니면, 각 exclusionFilter 에 대해 다음을 수행합니다:

      1. canonicalExclusionFilter정규화 한 결과로 둡니다.

      2. canonicalExclusionFilteruuidExclusionFilters 에 추가합니다.

    7. optionalServiceUUIDsArray.prototype.map.call(optionalServices, BluetoothUUID.getService) 로 둡니다.

    8. 어떤 BluetoothUUID.getService() 호출이라도 예외를 던지면, 그 예외를 던지고 단계를 중단합니다.

    9. optionalServiceUUIDs 에서 blocklisted 된 UUID를 제거합니다.

  6. descriptor 를 다음으로 둡니다:

    {
      name: "bluetooth",
      filters: uuidFilters
      optionalServices: optionalServiceUUIDs,
      optionalManufacturerData: optionalManufacturerData
      acceptAllDevices: filters !== null,
    }
    
  7. statedescriptor권한 상태 로 둡니다.

    참고: state비보안 컨텍스트 에서 강력한 기능을 사용할 수 없으므로 "denied" 입니다.
  8. state 가 "denied" 이면 [] 를 반환하고 단계를 중단합니다.

  9. UA가 다음 단계에서 장치를 전혀 찾을 수 없음을 증명할 수 있다면(예: 스캔에 사용할 Bluetooth 어댑터가 없거나, 필터가 어떤 가능한 광고 패킷과도 일치할 수 없는 경우), UA는 [] 를 반환하고 단계를 중단할 수 있습니다.

  10. scanResultscan for devicesglobalrequiredServiceUUIDs 와 함께 호출한 결과로 둡니다.

  11. filtersnull 이 아니면, 다음 하위 단계를 수행합니다:

    1. scanResult 에서 uuidFilters필터와 일치 하지 않는 장치를 제거합니다.

    2. exclusionFiltersnull 이 아니면, uuidExclusionFilters필터와 일치 하는 장치를 scanResult 에서 제거합니다.

  12. navigabledocumentnavigable 로 둡니다.

  13. promptId 를 새로운 고유한 불투명 문자열로 둡니다.

실제로는 프롬프트가 열려 있는 동안 장치 목록이 동적으로 업데이트됩니다. 명세 텍스트는 아직 이를 반영하지 않지만, 동일한 promptId 와 최신 장치 목록로 이벤트가 여러 번 발생할 수 있습니다. 참조: https://github.com/WebBluetoothCG/web-bluetooth/issues/621.

  1. 프롬프트 업데이트 이벤트 트리거navigable, promptId, scanResult 를 주어 실행합니다.

  2. scanResult 가 비어 있더라도, 사용자에게 선택을 요청 하여 descriptor 와 연계된 scanResult 의 장치들 중 하나를 선택하게 하고, 결과를 device 로 둡니다.

    UA는 사용자가 uuidFilters 와 일치하지 않는 근처 장치를 선택하도록 허용할 수 있습니다.

    참고: UA는 각 장치의 사람이 읽을 수 있는 이름을 사용자에게 보여주어야 합니다. 이 이름을 사용할 수 없는 경우(예: UA의 Bluetooth 시스템이 프라이버시 활성화 스캔을 지원하지 않는 경우), UA는 사용자가 관심을 표시하도록 허용하고 이름을 가져오기 위해 프라이버시 비활성화 스캔을 수행해야 합니다.
  3. 제거: map of navigables to device prompts[navigablenavigable id] 항목을 제거합니다.

  4. UA는 devicestorage 에 추가 할 수 있습니다.

    참고: device 를 선택하는 것은 사용자가 해당 장치가 적어도 현재 설정 객체 에 대해 "bluetooth"추가 권한 데이터allowedDevices 목록에 나타나길 의도한다는 의미일 가능성이 큽니다. 또한 mayUseGATT 필드는 true 여야 하며, requiredServiceUUIDsoptionalServiceUUIDs 의 합집합에 있는 모든 서비스가 기존 서비스에 더해 allowedServices 목록에 나타나야 합니다. 또한 optionalManufacturerData 의 제조사 코드들은 allowedManufacturerData 목록에 나타나야 합니다.
  5. device 가 "denied" 이면 [] 를 반환하고 단계를 중단합니다.

  6. UA는 device 의 모든 Service 로 Bluetooth 캐시 채우기 를 수행할 수 있습니다. 이 단계에서의 오류는 무시합니다.

  7. BluetoothDevice 가져오기 를 통해, 예외를 전파하면서 this 내에서 device 를 나타내는 객체를 얻고, 결과를 deviceObj 로 둡니다.

  8. [deviceObj] 를 반환합니다.

정규화 의 결과(대상: BluetoothLEScanFilterInit filter)는, 다음 단계에서 반환되는 BluetoothLEScanFilterInit 입니다:
  1. filter 의 어떤 멤버도 존재하지 않으면, TypeError 를 던지고 단계를 중단합니다.

  2. canonicalizedFilter{} 로 둡니다.

  3. filter.services 가 존재하면 다음 하위 단계를 수행합니다:

    1. filter.services.length === 0 이면 TypeError 를 던지고 단계를 중단합니다.

    2. servicesArray.prototype.map.call(filter.services, BluetoothUUID.getService) 로 둡니다.

    3. 어떤 BluetoothUUID.getService() 호출이라도 예외를 던지면, 그 예외를 던지고 단계를 중단합니다.

    4. services 의 어떤 서비스라도 blocklisted 이면, SecurityError 를 던지고 단계를 중단합니다.

    5. canonicalizedFilter.servicesservices 로 설정합니다.

  4. filter.name 이 존재하면 다음 하위 단계를 수행합니다.

    1. filter.nameUTF-8 인코딩 이 248 바이트를 초과하면 TypeError 를 던지고 단계를 중단합니다.

      참고: 248은 Bluetooth Device Name 의 최대 UTF-8 코드 유닛 수입니다.
    2. canonicalizedFilter.namefilter.name 으로 설정합니다.

  5. filter.namePrefix 가 존재하면 다음 하위 단계를 수행합니다.

    1. filter.namePrefix.length === 0 이거나 filter.namePrefixUTF-8 인코딩 이 248 바이트를 초과하면 TypeError 를 던지고 단계를 중단합니다.

      참고: 248은 Bluetooth Device Name 의 최대 UTF-8 코드 유닛 수입니다.
    2. canonicalizedFilter.namePrefixfilter.namePrefix 로 설정합니다.

  6. canonicalizedFilter["manufacturerData"][] 로 둡니다.

  7. filter["manufacturerData"] 가 존재하며 filter["manufacturerData"].length === 0 이면, TypeError 를 던지고 단계를 중단합니다.

  8. filter["manufacturerData"] 의 각 manufacturerData 에 대해 다음 하위 단계를 수행합니다:

    1. manufacturerData차단된 제조사 데이터 필터 이면, SecurityError 를 던지고 단계를 중단합니다.

    2. canonicalizedFilter["manufacturerData"] 에 객체 existing 이 존재하고, existing["companyIdentifier"] === manufacturerData["companyIdentifier"] 라면, TypeError 를 던지고 단계를 중단합니다.

    3. canonicalizedManufacturerDataFilter정규화 한 결과로(그리고 ECMAScript 값으로 변환 하여) 둡니다. 예외가 발생하면 예외를 전파하고 단계를 중단합니다.

    4. canonicalizedManufacturerDataFilter["companyIdentifier"]manufacturerData["companyIdentifier"] 로 설정합니다.

    5. canonicalizedManufacturerDataFiltercanonicalizedFilter["manufacturerData"] 에 추가합니다.

  9. canonicalizedFilter.serviceData[] 로 둡니다.

  10. filter["serviceData"] 가 존재하며 filter["serviceData"].length === 0 이면, TypeError 를 던지고 단계를 중단합니다.

  11. filter["serviceData"] 의 각 serviceData 에 대해 다음 하위 단계를 수행합니다:

    1. serviceBluetoothUUID.getService(serviceData["service"]) 로 둡니다. 예외가 발생하면 예외를 전파하고 단계를 중단합니다.

    2. serviceblocklisted 이면, SecurityError 를 던지고 단계를 중단합니다.

    3. canonicalizedServiceDataFilter정규화 한 결과로(그리고 ECMAScript 값으로 변환 하여) 둡니다. 예외가 발생하면 예외를 전파하고 단계를 중단합니다.

    4. canonicalizedServiceDataFilter["service"]service 로 설정합니다.

    5. canonicalizedServiceDataFiltercanonicalizedFilter["serviceData"] 에 추가합니다.

  12. canonicalizedFilter 를 반환합니다.

정규화의 결과는 BluetoothDataFilterInit filter에 대해 다음 단계를 수행한 뒤 반환되는 BluetoothDataFilterInit입니다:
  1. filter.dataPrefix 가 존재하지 않으면 dataPrefix 를 빈 바이트 시퀀스로 둡니다. 그렇지 않으면, 다음 하위 단계를 수행합니다:

    1. dataPrefix보유한 바이트의 사본으로 설정합니다(원본: filter.dataPrefix).

    2. dataPrefix 의 길이가 0이면 TypeError 를 던지고 이 단계를 중단합니다.

  2. filter.mask 가 존재하면 mask보유한 바이트의 사본으로 설정합니다(원본: filter.mask). 그렇지 않으면 maskdataPrefix 와 같은 길이의 0xFF 바이트 시퀀스로 둡니다.

  3. mask 의 길이가 dataPrefix 와 같지 않으면 TypeError 를 던지고 이 단계를 중단합니다.

  4. {dataPrefix: new Uint8Array(|dataPrefix|), mask: new Uint8Array(|mask|)} 를 반환합니다.

매개변수 global 과(와) 선택적인 Service UUIDs(기본값은 모든 UUID 집합)로 장치를 스캔하기 위해, UA는 다음 단계를 수행해야 합니다:
  1. UA가 최근 현재 스캔의 UUID 집합을 포함하는 상위 집합(UUID 세트)으로 장치를 스캔한 적이 있다면, UA는 그 스캔의 결과를 반환하고 이 단계를 중단할 수 있습니다.

    TODO: 시간 기준을 확정해야 합니다.

  2. nearbyDevicesBluetooth device 의 집합으로 두며, 초기값은 UA에 연결되어 있는(ATT Bearer 를 가진) 장치들의 집합과 동일합니다.

  3. topLevelTraversableglobalnavigable최상위 트래버서블로 둡니다.

  4. simulatedBluetoothDevices 를 빈 list 로 둡니다.

  5. topLevelTraversablesimulated Bluetooth adapter 가 있다면, simulatedBluetoothDevices 를 해당 값을 얻어 구성한 simulated Bluetooth device mapping 의 결과로 둡니다.

    비동기 장치 검색을 지원해야 합니다.

  6. UA가 LE 전송을 지원한다면 General Discovery Procedure 를 수행하되, Discoverable Mode 플래그가 설정되지 않은 장치도 포함할 수 있으며, 발견된 Bluetooth device 들을 nearbyDevices 에 추가합니다. UA는 Privacy Feature 를 활성화해야 합니다(SHOULD).

    passive scanningPrivacy Feature 는 모두 고유하고 불변인 장치 ID 누출을 방지합니다. UA가 둘 중 하나를 사용하도록 요구하는 것이 바람직하지만, OS API가 이를 노출하지 않는 것으로 보입니다. 또한 Bluetooth는 Central 장치가 Observation Procedure 를 지원하도록 요구하지 않기 때문에 passive scanning 사용을 어렵게 합니다.

  7. UA가 BR/EDR 전송을 지원한다면 Device Discovery Procedure 를 수행하고, 발견된 Bluetooth device 들을 nearbyDevices 에 추가합니다.

    모든 형태의 BR/EDR 조회/검색은 고유하고 불변인 장치 주소를 누출하는 것으로 보입니다.

  8. result 를 비어 있는 Bluetooth device 의 집합으로 둡니다.

  9. nearbyDevicessimulatedBluetoothDevices 내의 각 Bluetooth device device 에 대해 다음 하위 단계를 수행합니다:

    1. devicesupported physical transports 에 LE가 포함되어 있고, Bluetooth Device Name 이 부분적이거나 없으면, UA는 완전한 이름을 얻기 위해 Name Discovery Procedure 를 수행해야 합니다(SHOULD).

    2. device 가 광고하는 Service UUIDsService UUIDs 집합과 공통 원소를 가진다면(공집합이 아니라면), deviceresult 에 추가하고 이 하위 단계를 중단합니다.

      참고: BR/EDR 장치의 경우 Extended Inquiry Response 에서 GATT와 비-GATT 서비스를 구분할 방법이 없습니다. 사이트가 비-GATT 서비스의 UUID로 필터링하면, 사용자가 이 API로는 상호작용할 방법이 없는 장치를 requestDevice 결과로 선택할 수 있습니다.
    3. UA는 device 에 연결하고, UUID가 Service UUIDs 집합에 속하는 모든 Service 로 Bluetooth 캐시를 채우기 할 수 있습니다. devicesupported physical transports 에 BR/EDR이 포함된다면, 표준 GATT 절차에 더해 캐시를 채우는 동안 Service Discovery Protocol(Searching for Services)을 사용할 수 있습니다.

      참고: 주변의 모든 장치에 연결해 서비스를 발견하는 과정은 전력을 소모하고 Bluetooth 라디오의 다른 사용을 지연시킬 수 있습니다. UA는 해당 장치가 흥미로울 이유가 있는 경우에만 추가 서비스를 발견해야 합니다.

      또한 UA는 개발자가 이러한 추가 발견 동작에 의존하지 않도록 도와야 합니다. 예를 들어, 개발자가 이전에 특정 장치에 연결하여, UA가 그 장치가 지원하는 모든 서비스 집합을 알고 있는 경우를 생각해봅시다. 이후 개발자가 광고되지 않은 UUID로 필터링하면, 사용자 기기에서는 필터가 해당 장치를 제외할 가능성이 높음에도 개발자에게 표시되는 대화상자에는 그 장치가 포함될 수 있습니다. UA는 이러한 상황에서 경고하거나, 필터 일치 시 광고된 서비스만 포함하도록 하는 개발자 옵션을 제공할 수 있습니다.

    4. Bluetooth cachedevice 내부의, UUID가 Service UUIDs 집합에 속하는 존재가 확인된(known-present) Service 가 포함되어 있으면, UA는 deviceresult 에 추가할 수 있습니다.

  10. 스캔의 결과로 result 를 반환합니다.

흥미로운 장치가 범위 내에 들어왔을 때 사이트가 이벤트 수신을 등록할 수 있는 방법이 필요합니다.

허용된 Bluetooth device를 추가하기 위해, deviceBluetoothPermissionStorage storage 에, requiredServiceUUIDs 집합과 optionalServiceUUIDs 집합이 주어졌을 때, UA는 다음 단계를 수행해야 합니다:
  1. grantedServiceUUIDs 를 새 Set 으로 둡니다.

  2. requiredServiceUUIDs 의 내용을 grantedServiceUUIDs 에 추가합니다.

  3. optionalServiceUUIDs 의 내용을 grantedServiceUUIDs 에 추가합니다.

  4. storage.allowedDevices 내에서, deviceallowedDevice@[[device]] 와 동일한 요소 allowedDevice 를 찾습니다. 발견되면 다음 하위 단계를 수행합니다:

    1. allowedDevice.allowedServices 의 내용을 grantedServiceUUIDs 에 추가합니다.

    발견되지 않으면 다음 하위 단계를 수행합니다:

    1. allowedDevice.deviceId 를 고유 ID로 둡니다. 단, UA가 두 Bluetooth 연결이 동일한 장치인지 판별할 수 있는 한에서, 그리고 사용자가 그 사실을 스크립트에 노출하기를 원하는 범위 내에서만 고유해야 합니다.

  5. allowedDevice.allowedServicesgrantedServiceUUIDs 로 설정합니다.

  6. allowedDevice.mayUseGATTtrue 로 설정합니다.

허용된 Bluetooth device를 제거하기 위해, deviceBluetoothPermissionStorage storage 가 주어졌을 때, UA는 다음 단계를 수행해야 합니다:

  1. storage.allowedDevices 에서, deviceallowedDevice@[[device]] 와 동일한 요소 allowedDevice 를 찾습니다. 그러한 요소가 없으면 이 단계를 중단합니다.

  2. allowedDevicestorage.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("Lost permission", "NotFoundError");
  }
}).then(...);

Web Bluetooth API는 강력한 기능이며, name "bluetooth" 로 식별됩니다. 이에 대한 권한 관련 알고리즘과 타입은 다음과 같이 정의됩니다:

권한 디스크립터 타입
dictionary BluetoothPermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
  // These match RequestDeviceOptions.
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};
추가 권한 데이터 타입
BluetoothPermissionStorage로, 다음과 같이 정의됩니다:
dictionary AllowedBluetoothDevice {
  required DOMString deviceId;
  required boolean mayUseGATT;
  // An allowedServices of "all" means all services are allowed.
  required (DOMString or sequence<UUID>) allowedServices;
  required sequence<unsigned short> allowedManufacturerData;
};
dictionary BluetoothPermissionStorage {
  required sequence<AllowedBluetoothDevice> allowedDevices;
};

AllowedBluetoothDevice 인스턴스는 내부 슬롯 [[device]] 을 가지며, 이는 하나의 Bluetooth device 를 보관합니다.

추가 권한 데이터 제약
allowedDevices 의 각 원소는 서로 다른 [[device]] 와 서로 다른 deviceId 를 가져야 합니다.

mayUseGATTfalse 이면, allowedServicesallowedManufacturerData 는 모두 [] 여야 합니다.

참고: deviceId 는 한 시점에 보인 BluetoothDevice 인스턴스가 다른 시점(심지어 다른 realm 에서) 보인 인스턴스와 동일한 장치를 나타냄을 사이트가 추적할 수 있게 합니다. UA는 "bluetooth"추가 권한 데이터 를 반환할 때, 사용자가 그러한 추적이 이루어지기를 원하는지 원하지 않는지를 고려해야 합니다.

예를 들어, 일반적으로 사용자는 서로 다른 두 오리진이 자신이 동일한 장치와 상호작용 중임을 알기를 원하지 않으며, 오리진의 쿠키를 지운 뒤에도 고유 식별자가 지속되기를 원하지 않습니다.

권한 결과 타입
[Exposed=Window]
interface BluetoothPermissionResult : PermissionStatus {
  attribute FrozenArray<BluetoothDevice> devices;
};
권한 질의 알고리즘
BluetoothPermissionDescriptor descBluetoothPermissionResult status"bluetooth" 권한을 질의하려면, UA는 다음을 수행해야 합니다:
  1. status관련 전역 객체global 로 둡니다.

  2. status.statedesc권한 상태 로 설정합니다.

  3. status.state 가 "denied" 이면, status.devices 를 빈 FrozenArray 로 설정하고 이 단계를 중단합니다.

  4. matchingDevices 를 새 Array 로 둡니다.

  5. storage"bluetooth"추가 권한 데이터 로 두되, 대상은 현재 설정 객체 입니다.

  6. storage.allowedDevices 내의 각 allowedDevice 에 대해 다음 하위 단계를 수행합니다:

    1. desc.deviceId 가 설정되어 있고 allowedDevice.deviceId != desc.deviceId 이면, 다음 allowedDevice 로 넘어갑니다.

    2. desc.filters 가 설정되어 있으면 다음 하위 단계를 수행합니다:

      1. desc.filters 의 각 필터를 정규화 결과로 교체합니다. 정규화 중 오류가 발생하면 그 오류를 반환하고 이 단계를 중단합니다.

      2. allowedDevice.[[device]]desc.filters 내의 어떤 필터와도 일치하지 않으면, 다음 allowedDevice 로 넘어갑니다.

    3. BluetoothDevice 가져오기를 수행하여 global.navigator.bluetooth 내에서 allowedDevice.[[device]] 를 나타내는 객체를 얻고, 그 결과를 matchingDevices 에 추가합니다.

    참고: desc.optionalServicesdesc.optionalManufacturerData 필드는 결과에 영향을 주지 않습니다.
  7. status.devices 를 내용이 matchingDevices 인 새 FrozenArray 로 설정합니다.

권한 철회 알고리즘
사용자가 더 이상 노출하려 하지 않는 장치에 대해 Bluetooth 접근을 철회하려면, UA는 다음 단계를 수행해야 합니다:
  1. storage"bluetooth"추가 권한 데이터 로 두되, 대상은 현재 설정 객체 입니다.

  2. 현재 realm 내의 각 BluetoothDevice 인스턴스 deviceObj 에 대해 다음 하위 단계를 수행합니다:

    1. storage.AllowedBluetoothDeviceallowedDevice 가 존재하여, 다음을 모두 만족하면:

      deviceObj.[[allowedServices]]allowedDevice.allowedServices 로 갱신하고, 다음 deviceObj 로 넘어갑니다.

    2. 그렇지 않다면, 남은 단계를 수행해 deviceObj 를 해당 장치와 분리합니다.

    3. deviceObj.gatt.disconnect() 를 호출합니다.

      참고: 이는 deviceObjgattserverdisconnected 이벤트를 발생시킵니다.
    4. deviceObj.[[representedDevice]]null 로 설정합니다.

4.2. 전체 블루투스 사용 가능성

UA가 블루투스 라디오가 없는 컴퓨터에서 실행 중일 수 있습니다. requestDevice() 는 어떤 장치도 발견하지 못하도록 하여 이를 처리하며, 그 결과 NotFoundError 가 발생합니다. 다만 웹사이트는 이를 더 우아하게 처리할 수도 있습니다.

블루투스 어댑터가 있는 사용자에게만 블루투스 UI를 보여주려면:
const bluetoothUI = document.querySelector('#bluetoothUI');
navigator.bluetooth.getAvailability().then(isAvailable => {
  bluetoothUI.hidden = !isAvailable;
});
navigator.bluetooth.addEventListener('availabilitychanged', e => {
  bluetoothUI.hidden = !e.value;
});
getAvailability() 메서드는 호출되면 새로운 프라미스 promise 를 반환하고, 다음 단계를 병렬로 수행해야 합니다:
  1. globalthis관련 전역 객체 로 둡니다.

  2. global연결된 Document 가 "bluetooth" 라는 정책 제어 기능사용할 수 없음 이라면, 전역 작업을 대기 시켜 global 를 주고 resolve 하여 promisefalse 로 이행하고, 이 단계를 중단합니다.

  3. 사용자가 현재 오리진에 대해 이 함수의 반환값을 특정 값으로 구성해 둔 경우, 작업을 대기 시켜 구성된 값으로 resolve 하여 promise 를 이행하고, 이 단계를 중단합니다.

    참고: 사용자가 Web Bluetooth 권한을 차단한 경우, UA는 resolvepromisefalse 로 이행할 수 있습니다.
  4. simulatedBluetoothAdapterthisnavigable최상위 트래버서블simulated Bluetooth adapter 로 둡니다.

  5. simulatedBluetoothAdapter 가 비어 있지 않다면,

    1. simulatedBluetoothAdapter어댑터 상태 가 "absent" 이면, 전역 작업을 대기 시켜 global 를 주고 resolve 하여 promisefalse 로 이행합니다.

    2. simulatedBluetoothAdapterLE supported statefalse 이면, 전역 작업을 대기 시켜 global 를 주고 resolve 하여 promisefalse 로 이행합니다.

    3. 그 외의 경우, 전역 작업을 대기 시켜 global 를 주고 resolve 하여 promisetrue 로 이행합니다.

    4. 이 단계를 중단합니다.

  6. UA가 블루투스 라디오가 있는 시스템에서 실행 중인 경우, 블루투스 라디오의 전원 상태와 무관하게, 전역 작업을 대기 시켜 Bluetooth 작업 소스global 를 주고 resolve 하여 promisetrue 로 이행합니다.

  7. 그렇지 않다면, 전역 작업을 대기 시켜 Bluetooth 작업 소스global 를 주고 resolve 하여 promisefalse 로 이행합니다.

    참고: UA가 블루투스 사용 가능 여부를 판단하기 위해 다른 시스템을 조회할 수 있도록, 프라미스는 병렬로 이행됩니다.
사용자가 권한을 차단했고 UA가 getAvailability 프라미스를 false 로 이행하는 경우, 블루투스 UI를 다시 표시할 수 있도록 블루투스 사용 가능 상태를 감지하려면 다음을 사용할 수 있습니다:
function checkAvailability() {
  const bluetoothUI = document.querySelector('#bluetoothUI');
  navigator.bluetooth.getAvailability().then(isAvailable => {
    bluetoothUI.hidden = !isAvailable;
  });
}

navigator.permissions.query({name: "bluetooth"}).then(status => {
  if (status.state !== 'denied') checkAvailability();

  // Bluetooth is blocked, listen for change in PermissionStatus.
  status.onchange = () => {
    if (this.state !== 'denied') checkAvailability();
  };
});
UA가 블루투스를 사용할 수 있게 되거나 사용할 수 없게 되는 경우(예: 라디오가 물리적으로 연결/분리되었거나, getAvailability() 의 반환값에 대한 구성을 사용자가 변경한 경우 등), UA는 각 전역 객체 global 에 대해, 다음 단계를 실행하도록 전역 작업을 대기 시켜야 합니다 (Bluetooth 작업 소스 사용):
  1. 변경 이전에 getAvailability() 가 반환했을 값인 oldAvailability 를 둡니다.

  2. 변경 이후에 getAvailability() 가 반환할 값인 newAvailability 를 둡니다.

  3. oldAvailabilitynewAvailability 가 다르면,

    1. navigatorglobal연결된 Navigator 로 둡니다.

    2. bluetoothnavigator연결된 Bluetooth 로 둡니다.

    3. 이벤트를 발생 시키되, availabilitychanged 라는 이름과 ValueEvent 인터페이스를 사용하여 bluetooth 에서 발생시키고, 그 value 특성을 newAvailability 로 초기화합니다.

[
  Exposed=Window,
  SecureContext
]
interface ValueEvent : Event {
  constructor(DOMString type, optional ValueEventInit initDict = {});
  readonly attribute any value;
};

dictionary ValueEventInit : EventInit {
  any value = null;
};

ValueEvent 인스턴스는 DOM § 2.5 Constructing events 에 명시된 방식으로 구성됩니다.

value 특성은 초기화 시 설정된 값을 반환해야 합니다.

이러한 범용 이벤트 타입은 이곳이 아니라 [HTML] 또는 [DOM] 에 속합니다.

5. 장치 표현

UA는 Bluetooth 장치 속성을 여러 수준에서 추적해야 합니다: 전역, 오리진별, 그리고 전역 객체별.

5.1. 전역 Bluetooth 장치 속성

물리적 Bluetooth 장치는 UA가 수신하지 못했을 수도 있는 일부 속성을 보장할 수 있습니다. 이러한 속성은 여기서 선택적(optional)로 설명됩니다.

Bluetooth device는 다음 속성을 가집니다. 선택적 속성은 존재하지 않으며, 별도 설명이 있기 전까지 시퀀스와 맵 속성은 비어 있습니다. 그 외 속성은 기본값이 지정되어 있거나 장치가 소개될 때 지정됩니다.

UA는 두 Bluetooth device가 동일한 Bluetooth device인지 여부를, 두 장치가 동일한 Public Bluetooth Address, Static Address, Private Address, 또는 Identity Resolving Key를 갖고 있거나, 한 장치의 IRK와 다른 장치의 Resolvable Private Address를 사용한 Resolvable Private Address Resolution Procedure가 성공하는 경우에만 그리하다고 판단해야 합니다(SHOULD). 다만, 플랫폼 API가 장치 식별 방식을 문서화하지 않으므로 UA는 다른 절차를 사용할 수 있습니다(MAY).

5.2. BluetoothDevice

BluetoothDevice 인스턴스는 특정 전역 객체(또는 동치로, 특정 Realm 또는 Bluetooth 인스턴스)에 대한 Bluetooth device를 나타냅니다.

[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;
};
NOTE: BluetoothDevice 속성
id는 UA가 두 Bluetooth 연결이 동일한 장치로의 연결임을 판별할 수 있는 한도와, 사용자가 그 사실을 스크립트에 노출하기를 원하는 한도에서 장치를 고유하게 식별합니다.

name은 장치의 사람이 읽을 수 있는 이름입니다.

gatt 는 사이트에 권한이 있는 경우 이 장치의 GATT 서버와 상호작용하는 방법을 제공합니다.

forget() 은 사용자가 접근을 허가한 장치에 대한 접근을 페이지가 철회할 수 있게 합니다.

watchingadvertisements는 UA가 현재 이 장치의 광고를 스캔하고 그에 대한 이벤트를 발생시키는 경우 true입니다.

BluetoothDevice 인스턴스는 다음 표에 설명된 내부 슬롯과 함께 생성됩니다:

Internal Slot Initial Value Description (non-normative)
[[context]] <always set in prose> Bluetooth 객체가 반환한 BluetoothDevice.
[[representedDevice]] <always set in prose> 이 객체가 나타내는 Bluetooth device. 접근이 revoked된 경우 null.
[[gatt]] 새로운 BluetoothRemoteGATTServer 인스턴스이며, device 속성은 this로, connected 속성은 false로 초기화됩니다. 변하지 않습니다.
[[allowedServices]] <always set in prose> 이 오리진에 대한 이 장치의 allowedServices 목록. 모든 서비스가 허용된 경우 "all". 예: UA는 해당 오리진에서 URL을 광고한 referringDevice 의 모든 서비스에 오리진 접근을 허용할 수 있습니다.
[[allowedManufacturerData]] <always set in prose> 이 오리진에 대한 이 장치의 allowedManufacturerData 목록.
[[watchAdvertisementsState]] 'not-watching' 현재 watchAdvertisements() 동작의 상태를 설명하는 문자열 열거형. 가능한 열거형 값은 다음과 같습니다:
  • 'not-watching'

  • 'pending-watch'

  • 'watching'

get the BluetoothDevice representing을(를) 수행하여 Bluetooth device deviceBluetooth 인스턴스 context 내부에서 얻으려면, UA는 다음 단계를 수행해야 합니다:
  1. storageBluetoothPermissionStorage 로 두되, "bluetooth"extra permission data이며, 대상은 current settings object입니다.

  2. storage.allowedDevices 에서 allowedDevice.[[device]]devicesame deviceallowedDevice를 찾습니다. 그러한 객체가 없으면 SecurityError 를 던지고 단계를 중단합니다.

  3. context.[[deviceInstanceMap]]devicesame device인 키가 없다면, 다음 하위 단계를 수행합니다:

    1. resultBluetoothDevice 의 새 인스턴스로 둡니다.

    2. result의 모든 선택적 필드를 null로 초기화합니다.

    3. result.[[context]]context로 초기화합니다.

    4. result.[[representedDevice]]device로 초기화합니다.

    5. result.idallowedDevice.deviceId 로 초기화하고, result.[[allowedServices]]allowedDevice.allowedServices 로 초기화합니다.

    6. device에 부분 또는 전체 Bluetooth Device Name이 있으면, result.name을 해당 문자열로 설정합니다.

    7. result.watchingAdvertisementsfalse로 초기화합니다.

    8. context.[[deviceInstanceMap]]device에서 result로의 매핑을 추가합니다.

  4. context.[[deviceInstanceMap]] 에서 키가 devicesame device인 값을 반환합니다.

gatt 속성을 가져올 때는 다음 단계를 수행해야 합니다:
  1. "bluetooth"extra permission datathisrelevant settings object에 대해, 그 allowedDevices 목록 안에 allowedDevice.[[device]]this.[[representedDevice]]same device이고, allowedDevice.mayUseGATTtrue라면, this.[[gatt]] 를 반환합니다.

  2. 그렇지 않으면 null을 반환합니다.

forget() 메서드는 호출되면 새로운 프라미스 promise를 반환하고 다음 단계를 수행해야 합니다:
  1. device를 대상 BluetoothDevice 객체로 둡니다.

  2. storage를 현재 스크립트 실행 환경의 BluetoothPermissionStorage 객체로 둡니다.

  3. device를 storage에서 제거합니다. 이때 storage를 사용합니다.

  4. Resolve 하여 promise를 이행합니다.

사용자 에이전트는 watch advertisements manager를 연관 지니며, 이는 새 병렬 큐 시작의 결과입니다.

watchAdvertisements(options) 메서드는 호출되면 새로운 프라미스 promise를 반환하고 다음 단계를 수행해야 합니다:
  1. globalrelevant global object로 둡니다. 대상은 this입니다.

  2. options.signal 이 존재한다면 다음 하위 단계를 수행합니다:

    1. options.signalaborted 상태라면, abort watchAdvertisementsthis로 실행하고 단계를 중단합니다.

    2. 다음 중단 단계를 추가합니다. 대상: options.signal:

      1. Abort watchAdvertisementsthis로 실행합니다.

      2. Reject 하여 promiseAbortError로 거부합니다.

  3. this.[[watchAdvertisementsState]] 가 다음 중 하나인 경우:

    'not-watching'
    1. this.[[watchAdvertisementsState]]'pending-watch'로 설정합니다.

    2. 다음 단계를 큐에 넣어 watch advertisements manager에 전달합니다. 단, this.[[watchAdvertisementsState]]not-watching이 되면 중단합니다:

      1. UA가 이 장치의 광고를 스캔하고 있음을 보장합니다. UA는 동일 장치의 "중복" 광고를 필터링하지 않아야 합니다(SHOULD NOT).

      2. UA가 스캔 활성화에 실패하면, 전역 작업을 대기시켜 Bluetooth task sourceglobal을 주고 다음 단계를 수행한 뒤, 이 단계를 중단합니다:

        1. this.[[watchAdvertisementsState]]'not-watching'으로 설정합니다.

        2. Reject 하여 promise를 다음 오류 중 하나로 거부합니다:

          UA가 광고 스캔을 지원하지 않음

          NotSupportedError

          Bluetooth가 꺼져 있음

          InvalidStateError

          기타 사유

          UnknownError

      3. 전역 작업을 대기시켜 Bluetooth task sourceglobal을 주고 다음 단계를 수행합니다. 단, abort when this.[[watchAdvertisementsState]]not-watching이 되는 경우 중단합니다:

        1. this.[[watchAdvertisementsState]]watching으로 설정합니다.

        2. this.watchingAdvertisementstrue로 설정합니다.

        3. Resolve 하여 promiseundefined로 이행합니다.

    'pending-watch'
    1. Reject 하여 promiseInvalidStateError로 거부합니다.

    'watching'
    1. Resolve 하여 promiseundefined로 이행합니다.

  4. If aborted인 경우, reject 하여 promiseAbortError로 거부합니다.

Note: 스캔은 전력을 소모하므로 웹사이트는 불필요하게 광고를 관찰하지 않도록 해야 하며, 가능한 빨리 전력 사용을 중지하기 위해 AbortController를 사용해야 합니다.

abort watchAdvertisementsBluetoothDevice device에 대해 수행하려면, 다음 단계를 실행합니다:
  1. this.[[watchAdvertisementsState]]'not-watching'으로 설정합니다.

  2. device.watchingAdvertisementsfalse로 설정합니다.

  3. 다음 단계를 큐에 넣어 watch advertisements manager에 전달합니다:

    1. UA 전체에서 더 이상 어떤 BluetoothDevicewatchingAdvertisementstrue가 아니라면, UA는 광고 스캔을 중지해야 합니다(SHOULD). 그렇지 않고, this와 동일한 장치를 나타내는 BluetoothDevice 들 중 더 이상 watchingAdvertisementstrue인 것이 없다면, UA는 이 장치에 대한 리포트를 받지 않도록 스캔을 재구성해야 합니다.

abort all active watchAdvertisementsBluetooth bluetooth에 대해 수행하려면, 다음 단계를 실행합니다:
  1. For each device in bluetooth.[[deviceInstanceMap]] 에 대해 다음 단계를 수행합니다:

    1. device.[[watchAdvertisementsState]]pending-watch 또는 watching이라면, abort watchAdvertisementsdevice로 실행합니다.

5.2.1. 가시성 변경 처리

Bluetooth 장치 검색을 시작하는 동작은 표시 상태의 document에서만 실행될 수 있습니다. visibility state가 더 이상 "visible"이 아니면, 해당 document에 대한 스캔 동작을 중단해야 합니다.

이 명세는 visibilityStatedocument 가 주어졌을 때 다음의 페이지 가시성 변경 단계를 정의합니다:
  1. globaldocument관련 전역 객체로 둡니다.

  2. 전역 작업을 대기시켜 global 을 주고 Bluetooth 작업 소스에서 다음 단계를 수행합니다:

    1. navigatorglobal연결된 Navigator로 둡니다.

    2. bluetoothnavigator연결된 Bluetooth로 둡니다.

    3. visibilityState"visible" 이 아니면, 활성화된 모든 watchAdvertisements 동작을 bluetooth 에서 중단합니다.

5.2.2. 문서의 완전 활성 상태 상실 처리

Bluetooth 장치 검색을 시작하는 동작은 완전 활성 상태의 document에서만 실행될 수 있습니다. 완전 활성 상태가 손실되면, 해당 document에 대한 스캔 동작을 중단해야 합니다.

사용자 에이전트가 Document 가 더 이상 완전 활성이 아님을 판단하면, 다음 단계를 실행해야 합니다:
  1. document 를 더 이상 완전 활성이 아닌 Document 로 둡니다.

  2. globaldocument관련 전역 객체로 둡니다.

  3. 전역 작업을 대기시켜 global 을 주고 Bluetooth 작업 소스에서 다음 단계를 수행합니다:

    1. navigatorglobal연결된 Navigator로 둡니다.

    2. bluetoothnavigator연결된 Bluetooth로 둡니다.

    3. 활성화된 모든 watchAdvertisements 동작을 bluetooth 에서 실행하여 중단합니다.

5.2.3. 광고 이벤트에 응답

BluetoothDevice 에 대해 watchingAdvertisements 가 설정된 상태로 advertising event 가 도착하면, UA는 "advertisementreceived" 이벤트를 전달합니다.

[Exposed=Window, SecureContext]
interface BluetoothManufacturerDataMap {
  readonly maplike<unsigned short, DataView>;
};
[Exposed=Window, SecureContext]
interface BluetoothServiceDataMap {
  readonly maplike<UUID, DataView>;
};
[
  Exposed=Window,
  SecureContext
]
interface BluetoothAdvertisingEvent : Event {
  constructor(DOMString type, BluetoothAdvertisingEventInit init);
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute FrozenArray<UUID> uuids;
  readonly attribute DOMString? name;
  readonly attribute unsigned short? appearance;
  readonly attribute byte? txPower;
  readonly attribute byte? rssi;
  [SameObject]
  readonly attribute BluetoothManufacturerDataMap manufacturerData;
  [SameObject]
  readonly attribute BluetoothServiceDataMap serviceData;
};
dictionary BluetoothAdvertisingEventInit : EventInit {
  required BluetoothDevice device;
  sequence<(DOMString or unsigned long)> uuids;
  DOMString name;
  unsigned short appearance;
  byte txPower;
  byte rssi;
  BluetoothManufacturerDataMap manufacturerData;
  BluetoothServiceDataMap serviceData;
};
device 는 이 광고를 전송한 BluetoothDevice 입니다.

uuids 는 이 광고가 device 의 GATT 서버가 지원한다고 말하는 Service UUID 들을 나열합니다.

namedevice 의 로컬 이름 또는 그 접두사입니다.

appearanceAppearance 로, gap.appearance 특성에 의해 정의된 값 중 하나입니다.

txPower 는 장치가 브로드캐스트하는 송신 전력(dBm)입니다. 이는 경로 손실을 this.txPower - this.rssi 로 계산하는 데 사용됩니다.

rssi 는 광고가 수신된 전력(dBm)입니다. 이는 경로 손실을 this.txPower - this.rssi 로 계산하는 데 사용됩니다.

manufacturerDataunsigned short 회사 식별자 코드를 DataView 로 매핑합니다.

serviceDataUUIDDataView 로 매핑합니다.

장치를 가져와 iBeacon 데이터를 읽어들이기 위해, 개발자는 다음 코드를 사용할 수 있습니다. 이 API는 현재 특정 제조사 데이터를 기준으로 장치를 요청하는 방법을 제공하지 않으므로, 사용자가 requestDevice 대화상자에서 이 장치를 선택할 수 있도록 iBeacon 이 알려진 서비스를 포함하도록 광고를 순환시켜야 합니다.
var known_service = "A service in the iBeacon’s GATT server";
return navigator.bluetooth.requestDevice({
  filters: [{services: [known_service]}]
}).then(device => {
  device.watchAdvertisements();
  device.addEventListener('advertisementreceived', interpretIBeacon);
});

function interpretIBeacon(event) {
  var rssi = event.rssi;
  var appleData = event.manufacturerData.get(0x004C);
  if (appleData.byteLength != 23 ||
    appleData.getUint16(0, false) !== 0x0215) {
    console.log({isBeacon: false});
  }
  var uuidArray = new Uint8Array(appleData.buffer, 2, 16);
  var major = appleData.getUint16(18, false);
  var minor = appleData.getUint16(20, false);
  var txPowerAt1m = -appleData.getInt8(22);
  console.log({
      isBeacon: true,
      uuidArray,
      major,
      minor,
      pathLossVs1m: txPowerAt1m - rssi});
});

iBeacon 광고 형식은 Adam Warski의 How do iBeacons work?에서 유도되었습니다.

UA가 (광고 패킷과 선택적 스캔 응답으로 구성된) advertising event 를 수신하면, 다음 단계를 수행해야 합니다:
  1. device 를 해당 광고 이벤트를 전송한 Bluetooth device 로 둡니다.

  2. UA 내의 각 BluetoothDevice deviceObj 에 대해, devicedeviceObj.[[representedDevice]]동일한 장치 라면, deviceObj관련 설정 객체책임 이벤트 루프에 다음 하위 단계를 수행하도록 작업을 대기시킵니다:

    1. deviceObj.watchingAdvertisementsfalse 이면, 이 하위 단계를 중단합니다.

    2. advertising event 에 대한 advertisementreceived 이벤트 발생deviceObj 에서 수행합니다.

광고 이벤트 adv 에 대해 BluetoothDevice deviceObj 에서 advertisementreceived 이벤트를 발생시키려면, UA는 다음 단계를 수행해야 합니다:
  1. event 를 다음과 같이 둡니다

    {
      bubbles: true,
      device: deviceObj,
      uuids: [],
      manufacturerData: new Map(),
      serviceData: new Map()
    }
    
  2. adv 의 어떤 패킷에 대해서든 수신 신호 세기 가 사용 가능하면, event.rssi 를 dBm 단위의 해당 신호 세기로 설정합니다.

  3. adv 의 광고 패킷과 스캔 응답에 있는 각 AD 구조 에 대해, AD 타입에 따라 다음 단계 중에서 선택하여 수행합니다:

    16비트 Service UUIDs 불완전 목록
    16비트 Service UUIDs 완전 목록
    32비트 Service UUIDs 불완전 목록
    32비트 Service UUIDs 완전 목록
    128비트 Service UUIDs 불완전 목록
    128비트 Service UUIDs 완전 목록
    나열된 각 uuid 에 대해, 그것이 this.device.[[allowedServices]] 에 포함되어 있다면, uuidevent.uuids 에 추가합니다.
    단축 로컬 이름
    완전 로컬 이름
    AD 데이터를 UTF-8 BOM 없이 디코드하고, 그 결과를 event.name 에 설정합니다.
    참고: 이름이 완전한지 여부는 노출하지 않습니다. 기존 API에서는 이 정보를 얻기 위해 원시 광고를 읽어야 하고, API에 필드를 추가하기 전에 그것이 유용하다는 더 많은 근거가 필요합니다.
    제조사별 데이터
    각 16비트 회사 식별자 코드 manufacturerCode 에 대해, 그것이 this.device.[[allowedManufacturerData]] 에 포함되어 있고, 해당 제조사 데이터가 차단된 제조사 데이터 가 아니라면, manufacturerCode 를 키로 하고 제조사별 데이터를 담은 ArrayBuffer 를 값으로 하는 매핑을 event.manufacturerData 에 추가합니다.
    TX 전력 레벨
    event.txPower 를 AD 데이터로 설정합니다.
    서비스 데이터 - 16비트 UUID
    서비스 데이터 - 32비트 UUID
    서비스 데이터 - 128비트 UUID
    서비스 데이터의 각 UUID uuid 에 대해, 그것이 this.device.[[allowedServices]] 에 포함되어 있다면, uuid 를 키로 하고 서비스 데이터를 담은 ArrayBuffer 를 값으로 하는 매핑을 event.serviceData 에 추가합니다.
    Appearance
    event.appearance 를 AD 데이터로 설정합니다.
    그 외
    다음 AD 구조로 건너뜁니다.
  4. 이벤트를 발생시키되, 이름은 "advertisementreceived" 이고 BluetoothAdvertisingEventevent 로 초기화하여 사용하며, isTrusted 특성은 true 로 초기화하여, deviceObj 에서 발생시킵니다.

BluetoothAdvertisingEvent 의 모든 필드는 마지막으로 초기화되었거나 설정된 값을 반환합니다.

BluetoothAdvertisingEvent(type, init) 생성자는 다음 단계를 수행해야 합니다:
  1. DOM § 2.5 Constructing events 의 단계를 따르되, uuids, manufacturerData, serviceData 멤버는 제외하여 실행한 결과를 event 로 둡니다.

  2. init.uuids 가 설정되어 있으면, event.uuidsinit.uuids.map( BluetoothUUID.getService) 의 요소들을 담은 새로운 FrozenArray 로 초기화합니다. 그렇지 않으면 event.uuids 를 빈 FrozenArray 로 초기화합니다.

  3. init.manufacturerData 의 각 매핑에 대해:

    1. code 를 키를 unsigned short 로 변환한 값으로 둡니다.

    2. value 를 값으로 둡니다.

    3. valueBufferSource 가 아니면, TypeError 를 던집니다.

    4. bytes읽기 전용 ArrayBuffer 의 새 인스턴스로 두되, 보유한 바이트의 사본value 에 의해 채워지도록 합니다.

    5. event.manufacturerData.[[BackingMap]]code 를 키로 하고 new DataView(bytes) 를 값으로 추가합니다.

  4. init.serviceData 의 각 매핑에 대해:

    1. key 를 키로 둡니다.

    2. serviceBluetoothUUID.getService(key). 호출 결과로 둡니다.

    3. value 를 값으로 둡니다.

    4. valueBufferSource 가 아니면, TypeError 를 던집니다.

    5. bytes읽기 전용 ArrayBuffer 의 새 인스턴스로 두되, 보유한 바이트의 사본value 에 의해 채워지도록 합니다.

    6. event.serviceData.[[BackingMap]]service 를 키로 하고 new DataView(bytes) 를 값으로 추가합니다.

  5. 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 Server가 프로파일, 기본 Service, Included Service, Characteristic, 그리고 Descriptor의 계층을 어떻게 포함하는지를 설명합니다.

프로파일은 순수하게 논리적 개념입니다. 프로파일의 명세는 해당 프로파일이 포함하는 다른 GATT 엔터티 간의 예상 상호작용을 기술하지만, 장치가 어떤 프로파일을 지원하는지 질의하는 것은 불가능합니다.

GATT Client는 일련의 GATT 절차를 사용하여 장치의 Service, Characteristic, Descriptor를 검색하고 상호작용할 수 있습니다. 이 명세는 Service, Characteristic, Descriptor를 통칭하여 Attribute라고 부릅니다. 모든 Attribute는 UUID로 식별되는 타입을 가집니다. 각 Attribute는 또한 동일한 GATT Server 내 동일 타입의 다른 Attribute와 구분되는 16비트 Attribute Handle을 가집니다. Attribute는 개념적으로 그들이 속한 GATT Server 내에서 Attribute Handle 순서로 정렬되어 있지만, 플랫폼 인터페이스가 어떤 순서로든 Attribute를 제공할 수 있고, 그 순서가 Attribute Handle 순서와 일치함을 보장하지는 않습니다.

ServiceIncluded ServiceCharacteristic의 모음을 포함합니다. Included Service는 다른 Service에 대한 참조이며, 하나의 Service는 둘 이상의 Service에 의해 포함될 수 있습니다. Service가 GATT Server 바로 아래에 나타나면 Primary Services라고 하며, 다른 Service에 의해서만 포함되는 경우 Secondary Service이지만, Primary Service도 포함될 수 있습니다.

Characteristic은 바이트 배열인 값과 Descriptor의 모음을 포함합니다. Characteristic의 properties에 따라, GATT Client는 값을 읽거나 쓸 수 있고, 값이 변경될 때 알림을 등록할 수 있습니다.

마지막으로, Descriptor는 (역시 바이트 배열인) 값을 포함하며, 이는 해당 Characteristic을 설명하거나 구성합니다.

6.1.1. 연결 간 지속성

Bluetooth의 Attribute Caching 시스템은 결합(bonded)된 클라이언트가 한 연결에서 다음 연결로 Attribute에 대한 참조를 저장하도록 허용합니다. Web Bluetooth는 웹사이트가 접근 권한을 가진 장치에 대해 결합되어 있지 않다고 간주합니다: BluetoothRemoteGATTService, BluetoothRemoteGATTCharacteristic, BluetoothRemoteGATTDescriptor 객체는 연결 해제 시 무효화되며, 사이트는 다시 연결할 때 그것들을 다시 가져와야 합니다.

6.1.2. Bluetooth 캐시

UA는 장치에서 발견한 Service, Characteristic, Descriptor의 계층에 대한 Bluetooth cache를 유지해야 합니다(MUST). UA는 동일한 장치에 접근하는 여러 오리진 간에 이 캐시를 공유할 수 있습니다(MAY). 캐시의 각 잠재적 항목은 존재함(known-present), 존재하지 않음(known-absent), 또는 미상(unknown) 중 하나입니다. 캐시는 동일한 attribute에 대한 두 항목을 포함해서는 안 됩니다(MUST NOT). 캐시의 각 known-present 항목은 각 Bluetooth 인스턴스에 대해 선택적인 Promise<BluetoothRemoteGATTService>, Promise<BluetoothRemoteGATTCharacteristic>, 또는 Promise<BluetoothRemoteGATTDescriptor> 인스턴스와 연관됩니다.

참고: 예를 들어 사용자가 초기에는 비어 있는 Bluetooth cache에서 serviceA.getCharacteristic(uuid1) 함수를 호출하면, UA는 필요한 캐시 항목을 채우기 위해 Discover Characteristics by UUID 절차를 사용하고, 반환할 Promise를 이행하는 데 하나의 Characteristic만 필요하므로 절차를 조기에 종료할 수 있습니다. 그러면 serviceA 내부에서 UUID가 uuid1인 첫 번째 Characteristic은 known-present가 되고, 그 UUID를 가진 이후의 Characteristic은 unknown 상태로 남습니다. 사용자가 나중에 serviceA.getCharacteristics(uuid1)을 호출하면, UA는 Discover Characteristics by UUID 절차를 재개하거나 다시 시작해야 합니다. 만약 serviceA에 UUID가 uuid1인 Characteristic이 하나뿐임이 밝혀지면, 이후의 Characteristic들은 known-absent가 됩니다.

Bluetooth cache의 known-present 항목은 순서가 있습니다. 기본 Service는 장치 내에서 특정 순서로 나타나고, Included Service와 Characteristic은 각 Service 내에서 특정 순서로 나타나며, Descriptor는 각 Characteristic 내에서 특정 순서로 나타납니다. 그 순서는 장치의 Attribute Handle 순서를 따라야 합니다(SHOULD). 다만 장치의 순서를 사용할 수 없는 경우 UA는 다른 순서를 사용할 수 있습니다(MAY).

Bluetooth cache 채우기에서 어떤 설명과 일치하는 항목으로 캐시를 채우기 위해, UA는 다음 단계를 수행해야 합니다(MUST).
참고: 이 단계들은 블로킹될 수 있으므로, 이 알고리즘의 사용은 병렬로 이루어져야 합니다.
  1. [BLUETOOTH42]가 충분한 정보를 반환한다고 명시한 임의의 GATT 절차 시퀀스를 사용하여, 캐시의 모든 일치 항목을 known-present 또는 known-absent로 만들도록 시도합니다. 오류는 § 6.7 오류 처리에 설명된 대로 처리합니다.

  2. 이전 단계가 오류를 반환하면, 이 알고리즘에서도 그 오류를 반환합니다.

BluetoothDevice 인스턴스 deviceObj에서 어떤 설명과 일치하는 항목을 대상으로 Bluetooth cache 질의를 수행하려면, UA는 deviceObj.gatt-connection-checking wrapper새로운 프라미스 promise 주위에 만들어 반환하고, 다음 단계를 병렬로 수행해야 합니다:
  1. globaldeviceObj관련 전역 객체로 둡니다.

  2. 해당 설명과 일치하는 항목으로 Bluetooth cache를 채웁니다.

  3. 이전 단계가 오류를 반환하면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 rejectpromise를 해당 오류로 거부하고, 이 단계를 중단합니다.

  4. entries를 설명과 일치하는 known-present 캐시 항목들의 시퀀스로 둡니다.

  5. contextdeviceObj.[[context]]로 둡니다.

  6. result를 새로운 시퀀스로 둡니다.

  7. entries의 각 entry에 대해:

    1. 만약 context.[[attributeInstanceMap]]Promise<BluetoothGATT*> 인스턴스가 entry에 연관되어 있지 않다면, entry가 Service, Characteristic, Descriptor인지에 따라 BluetoothRemoteGATTService representing 생성, BluetoothRemoteGATTCharacteristic representing 생성, 또는 BluetoothRemoteGATTDescriptor representing 생성을 수행하고, 결과 Promise에 대한 entry → Promise 매핑을 context.[[attributeInstanceMap]]에 추가합니다.

    2. context.[[attributeInstanceMap]]에서 entry에 연관된 Promise<BluetoothGATT*> 인스턴스를 result에 추가합니다.

  8. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고, resolveresult의 모든 요소를 모두 대기한 결과로 promise를 이행합니다.

Represented(obj: Device or GATT Attribute)는 obj의 타입에 따라 다음을 반환합니다:
BluetoothDevice
obj.[[representedDevice]]
BluetoothRemoteGATTService
obj.[[representedService]]
BluetoothRemoteGATTCharacteristic
obj.[[representedCharacteristic]]
BluetoothRemoteGATTDescriptor
obj.[[representedDescriptor]]
GetGATTChildren( attribute: GATT Attribute,
single: boolean,
uuidCanonicalizer: function,
uuid: optional (DOMString or unsigned int),
allowedUuids: optional ("all" or Array<DOMString>),
child type: GATT declaration type),

을(를) 수행하기 위해 UA는 다음 단계를 수행해야 합니다:
  1. uuid가 존재하면, uuidCanonicalizer(uuid)의 결과로 설정합니다. uuidCanonicalizer가 예외를 던졌다면, 해당 예외로 거부된 프라미스를 반환하고 이 단계를 중단합니다.

  2. uuid가 존재하고 blocklisted라면, SecurityError거부된 프라미스를 반환하고 이 단계를 중단합니다.

  3. attribute의 타입에 따라 deviceObj를 다음과 같이 둡니다:

    BluetoothDevice
    attribute
    BluetoothRemoteGATTService
    attribute.device
    BluetoothRemoteGATTCharacteristic
    attribute.service.device
  4. deviceObj.gatt.connectedfalse이면, NetworkError거부된 프라미스를 반환하고 이 단계를 중단합니다.

  5. Represented(attribute)가 null이면, InvalidStateError거부된 프라미스를 반환하고 이 단계를 중단합니다.

    참고: 이는 Service나 Characteristic이 장치에서 제거되었거나 연결 해제로 무효화되었는데, 그 객체를 다시 사용한 경우에 발생합니다.

  6. deviceObjBluetooth cache 질의를 수행하여, 다음을 만족하는 항목을 찾습니다:

    • Represented(attribute) 내부에 있고,

    • child type가 기술하는 타입을 가지며,

    • UUID가 blocklisted가 아니고,

    • uuid가 존재하면, 그 UUID가 uuid이며,

    • allowedUuids가 존재하고 "all"이 아니라면, UUID가 allowedUuids에 포함되고,

    • single 플래그가 설정되었다면, 이들 중 첫 번째여야 합니다.

    promise를 결과로 둡니다.

  7. 이행 시 promiseresult로 이행되면, 다음을 수행합니다:

    • result가 비어 있으면, NotFoundError를 던집니다.

    • 그 외에, single 플래그가 설정되어 있으면 result의 첫 번째(유일한) 요소를 반환합니다.

    • 그 외에는 result를 반환합니다.

6.1.4. Service, Characteristic, Descriptor 식별

두 Service, Characteristic, 또는 Descriptor absame attribute인지 확인할 때, UA는 가능하면 absame device 안에 있고 동일한 Attribute Handle을 가진다면 동일하다고 판단해야 합니다(SHOULD). 하지만, 다음 조건 중 하나라도 만족한다면 absame attribute로 간주해서는 안 됩니다(MUST NOT):

참고: 이 정의가 느슨한 이유는 플랫폼 API가 Attribute Handle 동일성에 기초했는지 문서화하지 않은 자체의 정체성(아이덴티티) 개념을 노출하기 때문입니다.
참고: 두 자바스크립트 객체 xy가 Service, Characteristic, 또는 Descriptor를 나타내는 경우, x === y는 이 객체들이 Bluetooth cache 질의 알고리즘이 새 객체를 생성하고 캐시하는 방식 때문에 same attribute를 나타내는지 여부를 반환합니다.

6.2. BluetoothRemoteGATTServer

BluetoothRemoteGATTServer는 원격 장치의 GATT Server를 나타냅니다.

[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는 이 서버를 실행하는 장치입니다.

connected는 이 인스턴스가 this.device에 연결되어 있는 동안 true입니다. 예를 들어 다른 global object에 대한 다른 BluetoothRemoteGATTServer 인스턴스가 연결되어 있는 경우 등, UA가 물리적으로 연결된 동안에도 false일 수 있습니다.

더 이상 ECMAScript 코드가 BluetoothRemoteGATTServer 인스턴스 server를 관찰할 수 없게 되면, UA는 server.disconnect()를 실행해야 합니다(SHOULD).

참고: navigator.bluetooth.[[deviceInstanceMap]]BluetoothDevice 인스턴스가 저장되므로, 이는 적어도 내비게이션이 전역 객체를 해제하거나 탭/창을 닫아 browsing context가 파기되기 전에는 발생할 수 없습니다.
참고: 가비지 컬렉션 시 연결을 해제하면, UA가 원격 장치의 리소스를 불필요하게 계속 소비하지 않도록 보장합니다.

BluetoothRemoteGATTServer 인스턴스는 아래 표에 설명된 내부 슬롯과 함께 생성됩니다:

Internal Slot Initial Value Description (non-normative)
[[activeAlgorithms]] new Set() 이 서버의 연결을 사용하는 각 알고리즘에 대응하는 Promise를 포함합니다. disconnect()는 이 집합을 비워서 알고리즘이 실행 중에 해당 realm이 한 번이라도 연결 해제되었는지 판단할 수 있게 합니다.
[[automatedGATTConnectionResponse]] "not-expected" GATT 연결 시도의 시뮬레이션된 GATT 연결 응답 코드입니다.
connect() 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. 만약 this.device.[[representedDevice]]null이라면, "NetworkError" DOMException으로 거부된 프라미스를 반환합니다.

  3. UA가 현재 Bluetooth 시스템을 사용 중이라면, "NetworkError" DOMException으로 거부된 프라미스를 반환할 수 있습니다(MAY).

    구현체는 이 NetworkError를 피할 수 있을지도 모르지만, 현재로서는 사이트가 이 API의 사용을 직렬화하고 실패한 동작을 재시도할 수 있는 방법을 사용자에게 제공할 필요가 있습니다. [Issue #188]

  4. promise새 프라미스로 둡니다.

  5. this.connectedtrue이면, resolvepromisethis로 이행하고 promise를 반환합니다.

  6. this.[[activeAlgorithms]]promise를 추가합니다.

  7. 다음 단계를 병렬로 수행합니다:

    1. 만약 globalnavigabletop-level traversablesimulated Bluetooth adapter가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. gatt connection attempted 이벤트 트리거globalnavigablethis.device를 주어 수행합니다.

      2. this.[[automatedGATTConnectionResponse]]"not-expected"라면, "expected"로 설정합니다.

      3. this.[[automatedGATTConnectionResponse]]"expected"이면, 값이 변경될 때까지 대기합니다.

      4. responsethis.[[automatedGATTConnectionResponse]]의 값으로 둡니다.

      5. this.[[automatedGATTConnectionResponse]]"not-expected"로 설정합니다.

      6. response0이 아니면, 다음 하위 단계를 수행합니다:

        1. this.[[activeAlgorithms]]에서 promise를 제거합니다.

        2. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "NetworkError" DOMException으로 reject하여 promise를 거부하고, 이 단계를 중단합니다.

    2. 그 외의 경우, 다음 단계를 수행합니다:

      1. this.device.[[representedDevice]]ATT Bearer가 없으면, 다음 하위 단계를 수행합니다:

        1. ATT Bearer 생성을 시도하며, GAP Interoperability Requirements의 "Connection Establishment"에 설명된 절차를 사용합니다. this.[[activeAlgorithms]]에서 promise가 제거되면 이 시도를 중단합니다.

          참고: 연결 가능한 광고를 수신하지 않으면 이 절차는 영원히 대기할 수 있습니다. 더 이상 연결을 원하지 않으면 웹사이트는 disconnect()를 호출해야 합니다.
        2. 이 시도가 this.[[activeAlgorithms]]에서 promise가 제거되어 중단되었다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "AbortError" DOMException으로 reject하여 promise를 거부하고, 이 단계를 중단합니다.

        3. 다른 이유로 이 시도가 실패했다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "NetworkError" DOMException으로 reject하여 promise를 거부하고, 이 단계를 중단합니다.

        4. Exchange MTU 절차를 사용하여 지원되는 가장 큰 MTU를 협상합니다. 이 단계의 오류는 무시합니다.

        5. UA는 BR/EDR Bonding Procedure 또는 LE Bonding Procedure를 사용하여 원격 장치와의 결합을 시도할 수 있습니다(MAY).

          참고: 일반적으로는 결합 여부 및 시점에 대한 제어를 웹사이트에 제공하는 것이 더 바람직하지만, Core Bluetooth 플랫폼 API는 UA가 그러한 설정을 구현할 방법을 제공하지 않습니다. 결합이 없는 것보다 결합이 있는 것이 더 안전하므로, 이 명세는 가능한 플랫폼에서 UA가 기회적으로 결합을 생성하도록 허용합니다. 이는 제한된 characteristic에 접근할 때가 아니라 연결이 생성될 때 사용자에게 표시되는 페어링 대화상자를 유발할 수 있습니다.

    3. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 다음 하위 단계를 수행합니다:

      1. this.[[activeAlgorithms]]promise가 없다면, "AbortError" DOMException으로 reject하여 promise를 거부하고, garbage-collect the connectionthis.device.[[representedDevice]]에 대해 수행하고, 이 단계를 중단합니다.

      2. this.[[activeAlgorithms]]에서 promise를 제거합니다.

      3. this.device.[[representedDevice]]null이면, "NetworkError" DOMException으로 reject하여 promise를 거부하고, garbage-collect the connectionthis.device.[[representedDevice]]에 대해 수행하고, 이 단계를 중단합니다.

      4. this.connectedtrue로 설정합니다.

      5. Resolvepromisethis로 이행합니다.

  8. promise를 반환합니다.

disconnect() 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. 활성 connect() 호출을 중단시키기 위해 this.[[activeAlgorithms]]를 비웁니다.

  2. this.connectedfalse이면, 이 단계를 중단합니다.

  3. Clean up the disconnected devicethis.device에 대해 수행합니다.

  4. devicethis.device.[[representedDevice]]로 둡니다.

  5. Garbage-collect the connectiondevice에 대해 수행합니다.

device의 연결을 garbage-collect the connection하려면, UA는 다음 단계를 병렬로 수행해야 합니다:
  1. UA 안팎에서 이 API를 사용하지 않는 시스템이 deviceATT Bearer를 사용 중이라면, 이 알고리즘을 중단합니다.

  2. UA 전체의 모든 BluetoothDevice deviceObj에 대해:

    1. deviceObj.[[representedDevice]]devicesame device가 아니면, 다음 deviceObj로 넘어갑니다.

    2. deviceObj.gatt.connectedtrue이면, 이 알고리즘을 중단합니다.

    3. deviceObj.gatt.[[activeAlgorithms]]Promise가 포함되어 있고 그 Promise가 connect() 호출에서 온 것이라면, 이 알고리즘을 중단합니다.

  3. deviceATT Bearer를 파기합니다.

참고: 알고리즘들은, UA가 전체 시간 동안 연결 상태를 유지하고 알고리즘 종료 전에 BluetoothRemoteGATTServer가 다시 연결되더라도, 실행 중에 해당 서버가 연결 해제되었다면 실패해야 합니다. 이를 달성하기 위해 반환되는 Promise를 래핑합니다.

promise 주위에 gattServer-connection-checking wrapper를 생성하려면, UA는 다음을 수행해야 합니다:

  1. gattServer.connectedtrue이면, promisegattServer.[[activeAlgorithms]]에 추가합니다.

  2. 프라미스가 정착(settled)되면 반응합니다:

    • promiseresult로 이행되었다면:

      1. 만약 promisegattServer.[[activeAlgorithms]]에 있다면, 이를 제거하고 result를 반환합니다.

      2. 그렇지 않다면, NetworkError를 던집니다.

        참고: 이 오류는 메인 알고리즘 실행 중에 gattServer가 연결 해제되었기 때문에 던져집니다.
    • promiseerror로 거부되었다면:

      1. 만약 promisegattServer.[[activeAlgorithms]]에 있다면, 이를 제거하고 error를 던집니다.

      2. 그렇지 않다면, NetworkError를 던집니다.

        참고: 이 오류는 메인 알고리즘 실행 중에 gattServer가 연결 해제되었기 때문에 던져집니다.
getPrimaryService(service) 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. this.device.[[allowedServices]]"all"이 아니고, servicethis.device.[[allowedServices]]에 없다면, SecurityError거부된 프라미스를 반환하고 이 단계를 중단합니다.

  2. GetGATTChildren(attribute=this.device,
    single=true,
    uuidCanonicalizer=BluetoothUUID.getService,
    uuid=service,
    allowedUuids=this.device.[[allowedServices]],
    child type="GATT Primary Service")
    를 반환합니다

getPrimaryServices(service) 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. this.device.[[allowedServices]]"all"이 아니고, service가 존재하며 this.device.[[allowedServices]]에 없다면, SecurityError거부된 프라미스를 반환하고 이 단계를 중단합니다.

  2. GetGATTChildren(attribute=this.device,
    single=false,
    uuidCanonicalizer=BluetoothUUID.getService,
    uuid=service,
    allowedUuids=this.device.[[allowedServices]],
    child type="GATT Primary Service")
    를 반환합니다

6.3. BluetoothRemoteGATTService

BluetoothRemoteGATTService 는 GATT Service를 나타내며, 장치의 일부 동작을 캡슐화하는 특성(Characteristic) 모음과 다른 서비스와의 관계로 구성됩니다.

[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입니다(예: '0000180d-0000-1000-8000-00805f9b34fb'Heart Rate 서비스).

isPrimary 는 이 서비스의 유형이 기본(primary)인지 보조(secondary)인지 나타냅니다.

BluetoothRemoteGATTService 인스턴스는 아래 표에 설명된 내부 슬롯과 함께 생성됩니다:

Internal Slot Initial Value Description (non-normative)
[[representedService]] <always set in prose> 이 객체가 나타내는 Service이며, 서비스가 제거되었거나 무효화된 경우 null 입니다.
create a BluetoothRemoteGATTService representing 으로 Service service 를 나타내는 객체를 만들기 위해, UA는 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. promise새 프라미스로 둡니다.

  3. 다음 단계를 병렬로 수행합니다:

    1. resultBluetoothRemoteGATTService 의 새 인스턴스로 두고, 그 [[representedService]] 슬롯을 service 로 초기화합니다.

    2. BluetoothDevice representing 가져오기를 수행하여 service 가 나타나는 장치의 객체를 얻고, 이를 device 로 둡니다.

    3. 이전 단계에서 오류가 발생했다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 그 오류로 reject 하여 promise 를 거부하고, 이 단계를 중단합니다.

    4. result.devicedevice 로 초기화합니다.

    5. result.uuidservice 의 UUID로 초기화합니다.

    6. service 가 Primary Service 이면 result.isPrimarytrue 로, 그렇지 않으면 result.isPrimaryfalse 로 초기화합니다.

    7. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 resolve 하여 promiseresult 로 이행합니다.

  4. promise 를 반환합니다.

getCharacteristic(characteristic) 메서드는 이 Service 내부의 Characteristic 을 가져옵니다. 호출되면 다음을 반환해야 합니다:

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")

getCharacteristics(characteristic) 메서드는 이 Service 내부의 Characteristic 목록을 가져옵니다. 호출되면 다음을 반환해야 합니다:

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")

getIncludedService(service) 메서드는 이 Service 내부의 Included Service 를 가져옵니다. 호출되면 다음을 반환해야 합니다:

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")

getIncludedServices(service) 메서드는 이 Service 내부의 Included Service 목록을 가져옵니다. 호출되면 다음을 반환해야 합니다:

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")

6.4. BluetoothRemoteGATTCharacteristic

BluetoothRemoteGATTCharacteristic 는 GATT Characteristic 를 나타내며, 주변기기의 서비스에 대한 추가 정보를 제공하는 기본 데이터 요소입니다.

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTCharacteristic : EventTarget {
  [SameObject]
  readonly attribute BluetoothRemoteGATTService service;
  readonly attribute UUID uuid;
  readonly attribute BluetoothCharacteristicProperties properties;
  readonly attribute DataView? value;
  Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
  Promise<sequence<BluetoothRemoteGATTDescriptor>>
    getDescriptors(optional BluetoothDescriptorUUID descriptor);
  Promise<DataView> readValue();
  Promise<undefined> writeValue(BufferSource value);
  Promise<undefined> writeValueWithResponse(BufferSource value);
  Promise<undefined> writeValueWithoutResponse(BufferSource value);
  Promise<BluetoothRemoteGATTCharacteristic> startNotifications();
  Promise<BluetoothRemoteGATTCharacteristic> stopNotifications();
};
BluetoothRemoteGATTCharacteristic includes CharacteristicEventHandlers;
service 는 이 characteristic 이 속한 GATT 서비스입니다.

uuid 는 characteristic 의 UUID입니다(예: '00002a37-0000-1000-8000-00805f9b34fb' Heart Rate Measurement characteristic).

properties 는 이 characteristic 의 속성을 담습니다.

value 는 현재 캐시된 characteristic 값입니다. 이 값은 characteristic 값을 읽거나 알림(notification) 또는 표시(indication)를 통해 업데이트될 때 갱신됩니다.

BluetoothRemoteGATTCharacteristic 인스턴스는 아래 표에 설명된 내부 슬롯과 함께 생성됩니다:

Internal Slot Initial Value Description (non-normative)
[[representedCharacteristic]] <always set in prose> 이 객체가 나타내는 Characteristic 이며, characteristic 이 제거되었거나 무효화된 경우 null 입니다.
[[automatedCharacteristicReadResponse]] "not-expected" GATT characteristic 읽기 시도에 대한 시뮬레이션된 GATT characteristic 응답 코드입니다.
[[automatedCharacteristicReadResponseData]] Empty byte sequence GATT characteristic 읽기 시도에 대한 시뮬레이션된 GATT characteristic 응답 데이터입니다.
[[automatedCharacteristicWriteResponse]] "not-expected" GATT characteristic 쓰기 시도에 대한 시뮬레이션된 GATT characteristic 응답 코드입니다.
[[automatedCharacteristicSubscribeToNotificationsResponse]] "not-expected" GATT characteristic 알림 구독 시도에 대한 시뮬레이션된 GATT characteristic 응답 코드입니다.
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]] "not-expected" GATT characteristic 알림 구독 해지 시도에 대한 시뮬레이션된 GATT characteristic 응답 코드입니다.
create a BluetoothRemoteGATTCharacteristic representing 으로 Characteristic characteristic 을 나타내는 객체를 만들기 위해, UA는 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. promise새 프라미스로 둡니다.

  3. 다음 단계를 병렬로 수행합니다:

    1. resultBluetoothRemoteGATTCharacteristic 의 새 인스턴스로 두고, 그 [[representedCharacteristic]] 슬롯을 characteristic 으로 초기화합니다.

    2. result.service< 를 BluetoothRemoteGATTService 인스턴스에서 초기화하는데, 이는 characteristic 이 나타나는 Service 를 나타냅니다.

    3. result.uuidcharacteristic 의 UUID로 초기화합니다.

    4. Characteristic 로부터 BluetoothCharacteristicProperties 인스턴스 생성을 수행하고, 결과를 properties 로 둡니다.

    5. 이전 단계가 오류를 반환했다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 그 오류로 reject 하여 promise 를 거부하고, 이 단계를 중단합니다.

    6. result.propertiesproperties 로 초기화합니다.

    7. result.valuenull 로 초기화합니다. UA는 (이 값이 사용 가능하다면) characteristic 으로부터 가장 최근에 읽은 값을 담은 new DataViewnew ArrayBuffer 를 감싸도록 하여 result.value 를 초기화할 수 있습니다(MAY).

    8. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 resolve 하여 promiseresult 로 이행합니다.

  4. promise 를 반환합니다.

getDescriptor(descriptor) 메서드는 이 Characteristic 내부의 Descriptor 를 가져옵니다. 호출되면 다음을 반환해야 합니다:

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")

getDescriptors(descriptor) 메서드는 이 Characteristic 내부의 Descriptor 목록을 가져옵니다. 호출되면 다음을 반환해야 합니다:

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")

readValue() 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. gattthis.service.device.gatt 로 둡니다.

  3. this.uuidblocklisted for reads 에 해당하면, "SecurityError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  4. gatt.connectedfalse 이면, "NetworkError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  5. characteristicthis.[[representedCharacteristic]] 로 둡니다.

  6. characteristicnull 이면, "InvalidStateError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  7. gatt-connection-checking wrapper 로 감싼 새 프라미스 promise 를 반환하고, 다음 단계를 병렬로 수행합니다:

    1. characteristicpropertiesRead 비트가 설정되어 있지 않다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NotSupportedError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

    2. globalnavigabletop-level traversablesimulated Bluetooth adapter 가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. Trigger a simulated characteristic event 를 수행하되, globalnavigable, this.device, characteristic, read 를 인수로 제공합니다.

      2. this.[[automatedCharacteristicReadResponse]]"expected" 로 설정하고, 변경될 때까지 대기합니다.

      3. responsethis.[[automatedCharacteristicReadResponse]] 의 값으로 둡니다.

      4. this.[[automatedCharacteristicReadResponse]]"not-expected" 로 설정합니다.

      5. response0 이 아니면, 다음 하위 단계를 수행합니다:

        1. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      6. 그렇지 않으면, buffernew ArrayBuffer 로 두되, 그 내용은 this.[[automatedCharacteristicReadResponseData]] 가 되도록 합니다.

    3. 그 외의 경우(시뮬레이션이 아닌 경우), 다음 단계를 수행합니다:

      1. UA가 현재 Bluetooth 시스템을 사용 중이라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단할 수 있습니다(MAY).

        구현에서는 이 NetworkError 를 피할 수 있을 수도 있지만, 현재로서는 사이트가 이 API 사용을 직렬화하거나 실패한 작업을 재시도할 방법을 사용자에게 제공해야 합니다. [Issue #188]

      2. Characteristic Value Read 절차의 하위 절차들을 임의로 조합하여 characteristic 의 값을 가져오고, 그 값을 담은 new ArrayBufferbuffer 로 둡니다. 오류 처리는 § 6.7 오류 처리 에 따라 수행합니다.

    4. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 다음 단계를 수행합니다:

      1. promisegatt.[[activeAlgorithms]] 에 없다면, "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      2. 위 하위 절차들이 오류를 반환했다면, 해당 오류로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      3. new DataViewbuffer 로 생성하여 this.value 에 할당합니다.

      4. 이벤트를 발생시키되, 이름은 "characteristicvaluechanged" 이고 bubbles 속성은 true 로 초기화하여 this 에서 발생시킵니다.

      5. Resolve 하여 promisethis.value 로 이행합니다.

WriteCharacteristicValue( this: BluetoothRemoteGATTCharacteristic,
value: BufferSource,
response: string),

를 수행하기 위해, UA는 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. gattthis.service.device.gatt 로 둡니다.

  3. this.uuidblocklisted for writes 에 해당하면, "SecurityError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  4. bytesvalue 가 보유한 바이트의 복사본으로 둡니다.

  5. bytes 의 길이가 512 바이트를 초과하면( Long Attribute Values 에 따른 속성 값의 최대 길이), "InvalidModificationError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  6. gatt.connectedfalse 이면, "NetworkError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  7. characteristicthis.[[representedCharacteristic]] 로 둡니다.

  8. characteristicnull 이면, "InvalidStateError" DOMException 으로 거부된 프라미스 를 반환하고 이 단계를 중단합니다.

  9. gatt-connection-checking wrapper 로 감싼 새 프라미스 promise 를 반환하고, 다음 단계를 병렬로 수행합니다.

    1. Assert: response 는 "required", "never", "optional" 중 하나입니다.

    2. globalnavigabletop-level traversablesimulated Bluetooth adapter 가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. this.[[automatedCharacteristicWriteResponse]]"not-expected" 가 아니라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "InvalidStateError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      2. Trigger a simulated characteristic event 를 수행하되, globalnavigable, this.device, characteristic, write, bytes 를 인수로 제공합니다.

      3. this.[[automatedCharacteristicWriteResponse]]"expected" 로 설정하고, 변경될 때까지 대기합니다.

      4. responsethis.[[automatedCharacteristicWriteResponse]] 의 값으로 둡니다.

      5. this.[[automatedCharacteristicWriteResponse]]"not-expected" 로 설정합니다.

      6. response0 이 아니면, 다음 하위 단계를 수행합니다:

        1. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

    3. 그 외의 경우(시뮬레이션이 아닌 경우), 다음 단계를 수행합니다:

      1. UA가 현재 Bluetooth 시스템을 사용 중이라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단할 수 있습니다(MAY).

        구현에서는 이 NetworkError 를 피할 수 있을 수도 있지만, 현재로서는 사이트가 이 API 사용을 직렬화하거나 실패한 작업을 재시도할 방법을 사용자에게 제공해야 합니다. [Issue #188]

      2. bytescharacteristic 에 쓰기 위해 다음을 수행합니다:

        response 가 "required" 인 경우
        Write Characteristic Value 절차를 사용합니다.
        response 가 "never" 인 경우
        Write Without Response 절차를 사용합니다.
        그 외의 경우
        Characteristic Value Write 절차의 하위 절차들을 임의로 조합하여 사용합니다.
        오류 처리는 § 6.7 오류 처리 에 따라 수행합니다.
    4. 전역 작업을 대기시켜 global 에서 Bluetooth 작업 소스를 사용하여 다음 단계를 수행합니다:

      1. promisegatt.[[activeAlgorithms]] 에 없다면, "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      2. 위 절차가 오류를 반환했다면, 그 오류로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      3. this.valuenew DataView 로 설정하되, 이는 new ArrayBufferbytes 를 포함하도록 감싼 것입니다.

      4. Resolve 하여 promiseundefined 로 이행합니다.

사용 중단됨. 대신 writeValueWithResponse()writeValueWithoutResponse() 를 사용하세요.

writeValue(value) 메서드는 호출되면 다음을 반환해야 합니다

WriteCharacteristicValue( this=this,
value=value,
response="optional")

이 메서드는 하위 호환성만을 위한 것입니다. 새로운 구현에서는 이 메서드를 구현하지 않아야 합니다. [Issue #238]

writeValueWithResponse(value) 메서드는 호출되면 다음을 반환해야 합니다

WriteCharacteristicValue( this=this,
value=value,
response="required")

writeValueWithoutResponse(value) 메서드는 호출되면 다음을 반환해야 합니다

WriteCharacteristicValue( this=this,
value=value,
response="never")

UA는 알려진 각 GATT Characteristic 에서 그 characteristic 의 active notification context set 으로 알려진 Bluetooth 객체 집합으로의 매핑을 유지해야 합니다(MUST).

Note: 주어진 characteristic 에 대한 집합에는, 알림을 등록한 각 Realmnavigator.bluetooth 객체가 담깁니다. 장치가 연결 해제되면 모든 알림은 비활성화됩니다. 재연결 후에도 알림을 계속 받으려면 사이트는 startNotifications() 를 다시 호출해야 하며, startNotifications() 가 적용되기 전의 간극에서 일부 알림을 놓칠 수밖에 없는 위험이 있습니다.
startNotifications() 메서드는 호출되면 다음 단계를 수행해야 합니다. 알림 수신에 대한 자세한 내용은 § 6.6.4 Responding to Notifications and Indications 를 참조하세요.
  1. globalthis관련 전역 객체로 둡니다.

  2. gattthis.service.device.gatt 로 둡니다.

  3. this.uuidblocklisted for reads 에 해당하면, "SecurityError" DOMException 으로 거부된 프라미스 를 반환합니다.

  4. gatt.connectedfalse 이면, "NetworkError" DOMException 으로 거부된 프라미스 를 반환합니다.

  5. characteristicthis.[[representedCharacteristic]] 로 둡니다.

  6. characteristicnull 이면, "InvalidStateError" DOMException 으로 거부된 프라미스 를 반환합니다.

  7. gatt-connection-checking wrapper 로 감싼 새 프라미스 promise 를 반환하고, 다음 단계를 병렬로 수행합니다.

    1. characteristicpropertiesNotifyIndicate 비트가 모두 설정되어 있지 않다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 NotSupportedErrorreject 하여 promise 를 거부하고 이 단계를 중단합니다.

    2. characteristicactive notification context setnavigator.bluetooth 가 포함되어 있다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 resolve 하여 promisethis 로 이행하고 이 단계를 중단합니다.

    3. globalnavigabletop-level traversablesimulated Bluetooth adapter 가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. this.[[automatedCharacteristicSubscribeToNotificationsResponse]]"not-expected" 가 아니라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "InvalidStateError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      2. Trigger a simulated characteristic event 를 수행하되, globalnavigable, this.device, characteristic, subscribe-to-notifications 를 인수로 제공합니다.

      3. this.[[automatedCharacteristicSubscribeToNotificationsResponse]]"expected" 로 설정하고, 변경될 때까지 대기합니다.

      4. responsethis.[[automatedCharacteristicSubscribeToNotificationsResponse]] 의 값으로 둡니다.

      5. this.[[automatedCharacteristicSubscribeToNotificationsResponse]]"not-expected" 로 설정합니다.

      6. response0 이 아니면, 다음 하위 단계를 수행합니다:

        1. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      7. 그렇지 않으면, successtrue 로 둡니다.

    4. 그 외의 경우(시뮬레이션이 아닌 경우), 다음 단계를 수행합니다:

      1. UA가 현재 Bluetooth 시스템을 사용 중이라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단할 수 있습니다(MAY).

        구현에서는 이 NetworkError 를 피할 수 있을 수도 있지만, 현재로서는 사이트가 이 API 사용을 직렬화하거나 실패한 작업을 재시도할 방법을 사용자에게 제공해야 합니다. [Issue #188]

      2. characteristic 에 Client Characteristic Configuration descriptor 가 있다면, Characteristic Descriptors 절차를 사용하여 characteristicClient Characteristic Configuration descriptor 에서 Notification 또는 Indication 비트 중 하나가 설정되도록 해야 하며, 이는 characteristicproperties 의 제약과 일치해야 합니다. UA는 두 비트를 모두 설정하는 것을 피해야 하며(SHOULD), 두 비트가 모두 설정된 경우 value-change events 를 중복 제거해야 합니다(MUST). 오류 처리는 § 6.7 오류 처리 에 따라 수행합니다.

        Note: 일부 장치의 characteristic 은 properties 에 Notify 또는 Indicate 비트가 포함되지만 Client Characteristic Configuration descriptor 가 없는 경우가 있습니다. 이러한 표준 비준수 characteristic 은 일반적으로 무조건적으로 알림 또는 표시를 전송하므로, 이 명세는 애플리케이션이 해당 메시지를 단순히 구독하는 것을 허용합니다.
      3. 절차가 성공했다면, successtrue 로 둡니다.

    5. successtrue 이면, navigator.bluetoothcharacteristicactive notification context set 에 추가합니다.

    6. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 다음 단계를 수행합니다:

      1. promisegatt.[[activeAlgorithms]] 에 없다면, "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      2. 위 절차가 오류를 반환했다면, 그 오류로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      3. Resolve 하여 promisethis 로 이행합니다.

Note: 알림이 활성화된 이후, 발생하는 value-change events 는 현재의 microtask checkpoint 이후에 전달됩니다. 이는 개발자가 결과 프라미스의 .then 핸들러에서 이벤트 핸들러를 설정할 수 있도록 해줍니다.
stopNotifications() 메서드는, 호출되면 새 프라미스 promise 를 반환하고 다음 단계를 병렬로 수행해야 합니다:
  1. characteristicthis.[[representedCharacteristic]] 로 둡니다.

  2. characteristicnull 이면, 거부된 프라미스InvalidStateError 로 반환하고 이 단계를 중단합니다.

  3. characteristicactive notification context setnavigator.bluetooth 가 포함되어 있으면, 이를 제거합니다.

    1. globalnavigabletop-level traversablesimulated Bluetooth adapter 가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. this.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]"not-expected" 가 아니라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "InvalidStateError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

      2. Trigger a simulated characteristic event 를 수행하되, globalnavigable, this.device, characteristic, unsubscribe-from-notifications 를 전달합니다.

      3. this.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]"expected" 로 설정하고, 변경될 때까지 대기합니다.

      4. responsethis.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]] 의 값으로 둡니다.

      5. this.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]"not-expected" 로 설정합니다.

      6. response0 이 아니면, 다음 하위 단계를 수행합니다:

        1. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global 을 주고 "NetworkError" DOMException 으로 reject 하여 promise 를 거부하고 이 단계를 중단합니다.

    2. 그 외의 경우, 다음 단계를 수행합니다:

      1. characteristicactive notification context set 이 비게 되었고, 해당 characteristic 에 Client Characteristic Configuration descriptor 가 있다면, UA는 Characteristic Descriptors 절차 중 아무 것이나 사용하여 characteristicClient Characteristic Configuration descriptor 에서 NotificationIndication 비트를 해제해야 합니다(SHOULD).

  4. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 this관련 전역 객체를 주어 resolvepromisethis 로 이행합니다.

참고: 프라미스를 이행하기 위한 작업을 대기시키면, 알림으로 인한 value change events 가 프라미스가 이행된 뒤에 도착하지 않도록 보장합니다.

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;
};
Characteristic 로부터 BluetoothCharacteristicProperties 인스턴스를 생성하기 위해 UA는 다음 단계를 수행해야 합니다:
  1. propertiesObjBluetoothCharacteristicProperties의 새로운 인스턴스로 둡니다.

  2. propertiescharacteristic특성 속성으로 둡니다.

  3. propertiesObj의 속성들을 properties의 해당 비트로부터 초기화합니다:

    속성 비트
    broadcast Broadcast
    read Read
    writeWithoutResponse Write Without Response
    write Write
    notify Notify
    indicate Indicate
    authenticatedSignedWrites Authenticated Signed Writes
  4. 특성 속성의 Extended Properties 비트가 설정되어 있지 않다면, propertiesObj.reliableWritepropertiesObj.writableAuxiliariesfalse로 초기화합니다. 그렇지 않으면 다음 단계를 수행합니다:

    1. 탐색을 통해 Characteristic Extended Properties 디스크립터를 characteristic에 대해 찾고, 그 값을 읽어 extendedProperties에 담습니다. 오류 처리는 § 6.7 오류 처리에 따라 수행합니다.

      Characteristic Extended Properties가 주어진 Characteristic에 대해 확장 속성이 불변인지 명확하지 않습니다. 만약 불변이라면, UA가 이를 캐시하도록 허용되어야 합니다.

    2. 이전 단계가 오류를 반환했다면, 그 오류를 반환합니다.

    3. propertiesObj.reliableWriteextendedProperties의 Reliable Write 비트로부터 초기화합니다.

    4. propertiesObj.writableAuxiliariesextendedProperties의 Writable Auxiliaries 비트로부터 초기화합니다.

  5. propertiesObj를 반환합니다.

6.5. BluetoothRemoteGATTDescriptor

BluetoothRemoteGATTDescriptor는 GATT 디스크립터를 나타내며, 이는 Characteristic의 값에 대한 추가 정보를 제공합니다.

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTDescriptor {
  [SameObject]
  readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
  readonly attribute UUID uuid;
  readonly attribute DataView? value;
  Promise<DataView> readValue();
  Promise<undefined> writeValue(BufferSource value);
};
characteristic는 이 디스크립터가 속한 GATT characteristic 입니다.

uuid는 characteristic 디스크립터의 UUID입니다(예: '00002902-0000-1000-8000-00805f9b34fb' Client Characteristic Configuration 디스크립터).

value는 현재 캐시된 디스크립터 값입니다. 이 값은 디스크립터의 값을 읽을 때 갱신됩니다.

BluetoothRemoteGATTDescriptor 인스턴스는 아래 표에 설명된 내부 슬롯과 함께 생성됩니다:

Internal Slot Initial Value Description (non-normative)
[[representedDescriptor]] <always set in prose> 이 객체가 나타내는 디스크립터이며, 디스크립터가 제거되었거나 다른 이유로 무효화된 경우 null 입니다.
[[automatedDescriptorReadResponse]] "not-expected" GATT 디스크립터 읽기 시도에 대한 시뮬레이션된 GATT 디스크립터 응답 코드입니다.
[[automatedDescriptorReadResponseData]] Empty byte sequence GATT 디스크립터 읽기 시도에 대한 시뮬레이션된 GATT 디스크립터 응답 데이터입니다.
[[automatedDescriptorWriteResponse]] "not-expected" GATT 디스크립터 쓰기 시도에 대한 시뮬레이션된 GATT 디스크립터 응답 코드입니다.
BluetoothRemoteGATTDescriptor representing 생성을 위해, 디스크립터 descriptor에 대해 UA는 다음 단계를 수행해야 합니다.
  1. promise새로운 프라미스로 둡니다.

  2. 다음 단계를 병렬로 수행합니다:

    1. resultBluetoothRemoteGATTDescriptor의 새 인스턴스로 두고, 그 [[representedDescriptor]] 슬롯을 descriptor로 초기화합니다.

    2. result.characteristicBluetoothRemoteGATTCharacteristic 인스턴스에서 초기화하되, 이는 descriptor가 나타나는 Characteristic을 나타냅니다.

    3. result.uuiddescriptor의 UUID로부터 초기화합니다.

    4. result.valuenull로 초기화합니다. UA는 사용 가능한 경우, descriptor로부터 가장 최근에 읽은 값을 담은 new DataViewnew ArrayBuffer를 감싸도록 하여 result.value를 초기화할 수 있습니다(MAY).

    5. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 this관련 전역 객체를 주어 resolvepromiseresult로 이행시킵니다.

  3. promise를 반환합니다.

readValue() 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. gattthis.characteristic.service.device.gatt로 둡니다.

  3. this.uuid읽기 블록리스트에 해당하면, "SecurityError" DOMException으로 거부된 프라미스를 반환합니다.

  4. gatt.connectedfalse이면, "NetworkError" DOMException으로 거부된 프라미스를 반환합니다.

  5. descriptorthis.[[representedDescriptor]]로 둡니다.

  6. descriptornull이면, "InvalidStateError" DOMException으로 거부된 프라미스를 반환합니다.

  7. connection-checking wrapper로 감싼 새 프라미스 promisegatt에 대해 반환하고, 다음 단계를 병렬로 수행합니다:

    1. globalnavigabletop-level traversablesimulated Bluetooth adapter가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. this.[[automatedDescriptorReadResponse]]"not-expected"가 아니라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "InvalidStateError" DOMException으로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      2. Trigger a simulated descriptor event를 수행하되, globalnavigable, this.device, descriptor, read를 전달합니다.

      3. this.[[automatedDescriptorReadResponse]]"expected"로 설정하고, 변경될 때까지 대기합니다.

      4. responsethis.[[automatedDescriptorReadResponse]]의 값으로 둡니다.

      5. this.[[automatedDescriptorReadResponse]]"not-expected"로 설정합니다.

      6. response0이 아니면, 다음 하위 단계를 수행합니다:

        1. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "NetworkError" DOMException으로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      7. 그렇지 않으면, buffernew ArrayBuffer로 두되, 그 내용은 this.[[automatedDescriptorReadResponseData]]가 되도록 합니다.

    2. 그 외의 경우, 다음 단계를 수행합니다:

      1. UA가 현재 Bluetooth 시스템을 사용 중이라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "NetworkError" DOMException으로 reject하여 이 단계를 중단할 수 있습니다(MAY).

        구현에서는 이 NetworkError를 피할 수 있을 수도 있지만, 현재로서는 사이트가 이 API 사용을 직렬화하거나 실패한 작업을 재시도할 방법을 사용자에게 제공해야 합니다. [Issue #188]

      2. Read Characteristic Descriptors 또는 Read Long Characteristic Descriptors 하위 절차를 사용하여 descriptor의 값을 가져오고, 그 값을 담은 new ArrayBufferbuffer로 둡니다. 오류 처리는 § 6.7 오류 처리에 따라 수행합니다.

    3. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 다음 단계를 수행합니다:

      1. promisegatt.[[activeAlgorithms]]에 없다면, "NetworkError" DOMException으로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      2. 위 하위 절차가 오류를 반환했다면, 해당 오류로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      3. buffer로 생성한 new DataViewthis.value에 할당합니다.

      4. Resolvepromisethis.value로 이행합니다.

writeValue(value) 메서드는 호출되면 다음 단계를 수행해야 합니다:
  1. globalthis관련 전역 객체로 둡니다.

  2. gattthis.characteristic.service.device.gatt로 둡니다.

  3. this.uuid쓰기 블록리스트에 해당하면, "SecurityError" DOMException으로 거부된 프라미스를 반환합니다.

  4. bytesvalue가 보유한 바이트의 복사본으로 둡니다.

  5. bytes가 512바이트를 초과한다면(이는 Long Attribute Values에 따른 속성 값의 최대 길이), "InvalidModificationError" DOMException으로 거부된 프라미스를 반환합니다.

  6. gatt.connectedfalse이면, "NetworkError" DOMException으로 거부된 프라미스를 반환합니다.

  7. descriptorthis.[[representedDescriptor]]로 둡니다.

  8. descriptornull이면, "InvalidStateError" DOMException으로 거부된 프라미스를 반환합니다.

  9. connection-checking wrapper로 감싼 새 프라미스 promisegatt에 대해 반환하고, 다음 단계를 병렬로 수행합니다.

    1. globalnavigabletop-level traversablesimulated Bluetooth adapter가 비어 있지 않다면, 다음 단계를 수행합니다:

      1. this.[[automatedDescriptorWriteResponse]]"not-expected"가 아니라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "InvalidStateError" DOMException으로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      2. Trigger a simulated descriptor event를 수행하되, globalnavigable, this.device, descriptor, write, bytes를 전달합니다.

      3. this.[[automatedDescriptorWriteResponse]]"expected"로 설정하고, 변경될 때까지 대기합니다.

      4. responsethis.[[automatedDescriptorWriteResponse]]의 값으로 둡니다.

      5. this.[[automatedDescriptorWriteResponse]]"not-expected"로 설정합니다.

      6. response0이 아니면, 다음 하위 단계를 수행합니다:

        1. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "NetworkError" DOMException으로 reject하여 promise를 거부하고 이 단계를 중단합니다.

    2. 그 외의 경우, 다음 단계를 수행합니다:

      1. UA가 현재 Bluetooth 시스템을 사용 중이라면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 "NetworkError" DOMException으로 reject하여 이 단계를 중단할 수 있습니다(MAY).

        구현에서는 이 NetworkError를 피할 수 있을 수도 있지만, 현재로서는 사이트가 이 API 사용을 직렬화하거나 실패한 작업을 재시도할 방법을 사용자에게 제공해야 합니다. [Issue #188]

      2. Write Characteristic Descriptors 또는 Write Long Characteristic Descriptors 하위 절차를 사용하여 bytesdescriptor에 씁니다. 오류 처리는 § 6.7 오류 처리에 따라 수행합니다.

    3. 전역 작업을 대기시켜 Bluetooth 작업 소스에서 global을 주고 다음 단계를 수행합니다:

      1. promisegatt.[[activeAlgorithms]]에 없다면, "NetworkError" DOMException으로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      2. 위 하위 절차가 오류를 반환했다면, 해당 오류로 reject하여 promise를 거부하고 이 단계를 중단합니다.

      3. this.valuenew DataView로 설정하되, 이는 new ArrayBufferbytes를 포함하도록 감싼 것입니다.

      4. Resolvepromiseundefined로 이행합니다.

6.6. 이벤트

6.6.1. Bluetooth 트리

Bluetooth treenavigator.bluetoothBluetoothDevice, BluetoothRemoteGATTService, BluetoothRemoteGATTCharacteristic, 또는 BluetoothRemoteGATTDescriptor 인터페이스를 구현하는 객체들이 트리에 참여하는 구조를 가리키는 명칭입니다.

6.6.2. 이벤트 타입

advertisementreceived
BluetoothDevice에서, 해당 장치로부터 광고 이벤트를 수신했을 때 발생합니다.
availabilitychanged
navigator.bluetooth에서, Bluetooth 시스템 전체가 UA에 사용 가능하거나 불가능해질 때 발생합니다.
characteristicvaluechanged
BluetoothRemoteGATTCharacteristic에서, 그 값이 변경될 때 발생합니다. 이는 읽기 요청의 결과이거나 값 변경 알림/표시일 수 있습니다.
gattserverdisconnected
BluetoothDevice에서 활성 GATT 연결이 끊어졌을 때 발생합니다.
serviceadded
새로운 BluetoothRemoteGATTService원격 장치에서 발견되었을 때, Bluetooth 트리에 추가된 직후 발생합니다.
servicechanged
BluetoothRemoteGATTService에서 그 상태가 변경될 때 발생합니다. 여기에는 서비스에서 추가되거나 제거되는 모든 특성 및/또는 디스크립터, 그리고 원격 장치로부터의 Service Changed 표시가 포함됩니다.
serviceremoved
BluetoothRemoteGATTService그 장치에서 제거되었을 때, Bluetooth 트리에서 제거되기 직전에 발생합니다.

6.6.3. 연결 해제에 대한 응답

Bluetooth 장치 deviceATT Bearer가 손실되었을 때(예: 원격 장치가 범위를 벗어났거나 사용자가 플랫폼 기능으로 연결을 끊은 경우), 각 BluetoothDevice deviceObj에 대해 UA는 전역 작업을 대기시켜, Bluetooth 작업 소스에서 deviceObj관련 전역 객체를 주어 다음 단계를 수행해야 합니다:
  1. deviceObj.[[representedDevice]]같은 장치device가 아니라면, 이 단계를 중단합니다.

  2. !deviceObj.gatt.connected이면, 이 단계를 중단합니다.

  3. 연결이 끊긴 장치 정리 deviceObj를 수행합니다.

clean up the disconnected device deviceObj를 수행하기 위해, UA는 다음을 수행해야 합니다:
  1. deviceObj.gatt.connectedfalse로 설정합니다.

  2. deviceObj.gatt.[[activeAlgorithms]]를 비웁니다.

  3. deviceObj.gatt.[[automatedGATTConnectionResponse]]"not-expected"로 설정합니다.

  4. contextdeviceObj.[[context]]로 둡니다.

  5. context.[[attributeInstanceMap]]에서, 키가 deviceObj.[[representedDevice]]에 속하는 모든 항목을 제거합니다.

  6. BluetoothRemoteGATTService service에 대해, deviceObjrealm 안에 있는 경우 service.[[representedService]]null로 설정합니다.

  7. BluetoothRemoteGATTCharacteristic characteristic에 대해, deviceObjrealm 안에 있는 경우 다음 하위 단계를 수행합니다:

    1. notificationContextscharacteristic.[[representedCharacteristic]]active notification context set으로 둡니다.

    2. notificationContexts에서 context를 제거합니다.

    3. notificationContexts가 비게 되었고, 여전히 ATT BearerdeviceObj.[[representedDevice]]에 대해 존재하며, 또한 characteristicClient Characteristic Configuration 디스크립터가 있다면, UA는 Characteristic Descriptors 절차 중 아무 것이나 사용하여 characteristicClient Characteristic Configuration 디스크립터에서 NotificationIndication 비트를 해제해야 합니다(SHOULD).

    4. characteristic.[[representedCharacteristic]]null로 설정합니다.

  8. BluetoothRemoteGATTDescriptor descriptor에 대해, deviceObjrealm 안에 있는 경우 descriptor.[[representedDescriptor]]null로 설정합니다.

  9. 이벤트를 발생시키되, 이름은 gattserverdisconnected이고, 그 bubbles 속성은 true로 초기화하여 deviceObj에서 발생시킵니다.

    Note: 이 이벤트는 BluetoothRemoteGATTServer에서 발생하지 않습니다.

6.6.4. 알림과 표시(Indication)에 대한 응답

UA가 Bluetooth Characteristic Value Notification 또는 Indication을 수신하면, 다음 단계를 수행해야 합니다:
  1. 해당 특성의 active notification context set에 있는 각 bluetoothGlobal에 대해, 그 관련 전역 객체를 기준으로 전역 작업을 대기시켜 다음 하위 단계를 수행합니다:

    1. characteristicObject를, bluetoothGlobal를 루트로 하는 Bluetooth 트리에서 해당 Characteristic을 나타내는 BluetoothRemoteGATTCharacteristic로 둡니다.

    2. characteristicObject .service.device.gatt.connectedfalse이면, 이 하위 단계를 중단합니다.

    3. characteristicObject.value를, 새로운 DataView로 설정하되, 이는 새로운 ArrayBuffer를 감싸며, 해당 Characteristic의 새로운 값을 보유해야 합니다.

    4. 이벤트를 발생시키되, 이름은 characteristicvaluechanged이고, bubbles 속성은 true로 초기화하여 characteristicObject에서 발생시킵니다.

6.6.5. 서비스 변경에 대한 응답

Bluetooth Attribute Caching 시스템은 클라이언트가 Service, Characteristic, Descriptor의 변경을 추적할 수 있게 합니다. 웹 페이지에 노출하기 위한 목적의 속성들을 검색하기 전에, UA는 해당 특성이 존재한다면 Service Changed 특성으로부터 표시(Indication)를 구독해야 합니다. UA가 Service Changed 특성에 대한 표시를 수신하면, 다음 단계를 수행해야 합니다.
  1. removedAttributes를, 표시에서 지정한 범위 내에서 UA가 표시 이전에 검색했던 속성들의 목록으로 둡니다.

  2. Primary Service Discovery, Relationship Discovery, Characteristic Discovery, Characteristic Descriptor Discovery 절차를 사용해, Service Changed 특성에 의해 지정된 범위 내의 속성들을 다시 검색합니다. UA는 아래에서 발생하는 이벤트에 영향을 미칠 수 없음을 증명할 수 있다면 지정된 범위의 전부 또는 일부 검색을 생략해도 됩니다(MAY).

  3. addedAttributes를, 이전 단계에서 검색된 속성들의 목록으로 둡니다.

  4. 서비스 상호운용성 요구사항에 정의된 바(Characteristic과 Descriptor 값은 무시)를 기준으로 동일한 정의를 가진 속성이 removedAttributesaddedAttributes 모두에 나타난다면, 양쪽 목록에서 제거합니다.

    다음과 같은 장치 상태를 가정합니다:
    상태 1
    • Service A
      • Characteristic C: value [1, 2, 3]
    • Service B
    상태 2
    • Service A
      • Characteristic C: value [3, 2, 1]
    • Service B
    상태 3
    • Service A
      • Characteristic D: value [3, 2, 1]
    • Service B
    상태 4
    • Service A
      • Characteristic C: value [1, 2, 3]
    • Service B
      • Include Service A

    상태 1에서 2로의 전이는, 특성 및 디스크립터 값을 무시할 때 서비스 A를 “동일한 정의”로 남기므로, removedAttributesaddedAttributes 양쪽에서 제거되며, 어떤 servicechanged 이벤트에도 나타나지 않습니다.

    상태 1에서 3으로의 전이는, 서비스 정의에 특성 정의가 포함되므로 서비스 A를 다른 정의로 남기게 됩니다. 따라서 서비스 A는 removedAttributesaddedAttributes에 모두 남습니다. 이후 단계 8에서 서비스는 changedServices로 이동하여, servicechanged 이벤트만 발생시키고, serviceaddedserviceremoved를 둘 다 발생시키지는 않습니다. 또한 단계 9에서는 특성 C가 제거되고 특성 D가 추가되었으므로 서비스 A가 changedServices에 추가됩니다.

    상태 1에서 4로의 전이는 1→3 전이와 유사합니다. 서비스 B는 단계 8에서 changedServices로 이동하지만, 특성이나 디스크립터가 변경되지 않았으므로 단계 9에서 중복으로 추가되지는 않습니다.

  5. invalidatedAttributes를, removedAttributes에는 있지만 addedAttributes에는 없는 속성들로 둡니다.

  6. UA의 각 environment settings object settings에 대해, 해당 responsible event loop작업을 대기시켜 다음 하위 단계를 수행합니다:

    1. BluetoothRemoteGATTService service 각각에 대해, 그 관련 설정 객체settings인 경우, service.[[representedService]]invalidatedAttributes에 있다면 service.[[representedService]]null로 설정합니다.

    2. BluetoothRemoteGATTCharacteristic characteristic 각각에 대해, 그 관련 설정 객체settings인 경우, characteristic.[[representedCharacteristic]]invalidatedAttributes에 있다면 characteristic.[[representedCharacteristic]]null로 설정합니다.

    3. BluetoothRemoteGATTDescriptor descriptor 각각에 대해, 그 관련 설정 객체settings인 경우, descriptor.[[representedDescriptor]]invalidatedAttributes에 있다면 descriptor.[[representedDescriptor]]null로 설정합니다.

    4. globalsettingsglobal object로 둡니다.

    5. global.navigator.bluetooth.[[attributeInstanceMap]]에서, invalidatedAttributes에 있는 속성을 나타내는 모든 항목을 제거합니다.

  7. changedServices를, 처음에는 비어 있는 Service 집합으로 둡니다.

  8. 동일한 ServiceremovedAttributesaddedAttributes 모두에 나타나면, 양쪽에서 제거하고 changedServices에 추가합니다.

  9. removedAttributes 또는 addedAttributes에 있는 각 CharacteristicDescriptor에 대해, 원래 목록에서 제거하고 그 부모 ServicechangedServices에 추가합니다.

    Note: 이 시점 이후, removedAttributesaddedAttributes에는 Service만 남습니다.
  10. addedAttributes에 있는 어떤 Service가, 만약 그 호출 시점에 존재했다면 이전의 어떤 getPrimaryService, getPrimaryServices, getIncludedService, getIncludedServices 호출에서도 반환되지 않았을 경우, UA는 해당 ServiceaddedAttributes에서 제거해도 됩니다(MAY).

  11. changedDevices를, removedAttributes, addedAttributes, changedServices 중 어떤 Service라도 포함하는 Bluetooth 장치 집합으로 둡니다.

  12. BluetoothDevice deviceObj 각각에 대해, 해당 장치가 changedDevices의 장치에 연결되어 있다면, 전역 작업을 대기시켜 Bluetooth 작업 소스에서 deviceObj관련 전역 객체를 주고 다음 단계를 수행합니다:

    1. Service service에 대해, removedAttributes에 있는 경우:

      1. deviceObj.[[allowedServices]]"all"이거나 해당 서비스의 UUID를 포함한다면, 이벤트를 발생시키되, 이름은 serviceremoved이고, bubbles 속성은 true로 초기화하여, 해당 Service를 나타내는 BluetoothRemoteGATTService에서 발생시킵니다.

      2. BluetoothRemoteGATTServiceBluetooth 트리에서 제거합니다.

    2. addedAttributes에 있는 각 Service에 대해, deviceObj.[[allowedServices]]"all"이거나 해당 서비스의 UUID를 포함한다면, 해당 Service를 나타내는 BluetoothRemoteGATTServiceBluetooth 트리에 추가한 다음, 이벤트를 발생시키되, 이름은 serviceadded이고, bubbles 속성은 true로 초기화하여 해당 BluetoothRemoteGATTService에서 발생시킵니다.

    3. changedServices에 있는 각 Service에 대해, deviceObj.[[allowedServices]]"all"이거나 해당 서비스의 UUID를 포함한다면, 이벤트를 발생시키되, 이름은 servicechanged이고, bubbles 속성은 true로 초기화하여 해당 BluetoothRemoteGATTService에서 발생시킵니다.

6.6.6. IDL 이벤트 핸들러

[SecureContext]
interface mixin CharacteristicEventHandlers {
  attribute EventHandler oncharacteristicvaluechanged;
};

oncharacteristicvaluechangedEvent handler IDL attribute로, characteristicvaluechanged 이벤트 타입에 해당합니다.

[SecureContext]
interface mixin BluetoothDeviceEventHandlers {
  attribute EventHandler onadvertisementreceived;
  attribute EventHandler ongattserverdisconnected;
};

onadvertisementreceivedEvent handler IDL attribute로, advertisementreceived 이벤트 타입에 해당합니다.

ongattserverdisconnectedEvent handler IDL attribute로, gattserverdisconnected 이벤트 타입에 해당합니다.

[SecureContext]
interface mixin ServiceEventHandlers {
  attribute EventHandler onserviceadded;
  attribute EventHandler onservicechanged;
  attribute EventHandler onserviceremoved;
};

onserviceaddedEvent handler IDL attribute로, serviceadded 이벤트 타입에 해당합니다.

onservicechangedEvent handler IDL attribute로, servicechanged 이벤트 타입에 해당합니다.

onserviceremovedEvent handler IDL attribute로, serviceremoved 이벤트 타입에 해당합니다.

6.7. 오류 처리

Note: 이 절은 주로 시스템 오류를 JavaScript 오류 이름으로 매핑하고, UA가 특정 작업을 재시도할 수 있도록 허용합니다. 재시도 로직과 가능한 오류 구분은 운영체제에 크게 제약되므로, 여기 요구사항이 현실과 다른 경우는 브라우저 버그라기보다 명세 버그일 가능성이 큽니다.
UA가 어떤 알고리즘의 단계를 실행하거나 Bluetooth 캐시에 대한 쿼리를 처리하기 위해 GATT 절차(둘 다 이하 “단계”라 함)를 사용하고 있을 때, 해당 GATT 절차가 Error Response를 반환하면, UA는 다음 단계를 수행해야 합니다:
  1. 절차가 시간 초과되거나, (Profile Fundamentals에 서술된) ATT Bearer가 어떤 이유로든 없거나 종료되었다면, 해당 단계에서 NetworkError를 반환하고 이 단계를 중단합니다.

  2. Error Code에 따라 다음과 같이 처리합니다:

    Invalid PDU
    Invalid Offset
    Attribute Not Found
    Unsupported Group Type
    이 오류 코드는 프로토콜 계층에서 예상치 못한 일이 발생했음을 나타내며, UA 또는 장치 버그일 가능성이 큽니다. 해당 단계에서 NotSupportedError를 반환합니다.
    Invalid Handle
    해당 단계에서 InvalidStateError를 반환합니다.
    Invalid Attribute Value Length
    해당 단계에서 InvalidModificationError를 반환합니다.
    Attribute Not Long

    “Long” 하위 절차를 사용하지 않았는데 이 오류를 받은 경우, 장치 버그일 수 있습니다. 해당 단계에서 NotSupportedError를 반환합니다.

    그렇지 않으면, “Long” 하위 절차 없이 해당 단계를 재시도합니다. 기록할 값의 길이 때문에 이것이 불가능하다면, 해당 단계에서 InvalidModificationError를 반환합니다.

    Insufficient Authentication
    Insufficient Encryption
    Insufficient Encryption Key Size
    UA는 연결의 보안 수준을 높이도록 시도해야 합니다(SHOULD). 이 시도가 실패하거나 UA가 더 높은 보안을 지원하지 않는다면, 해당 단계에서 SecurityError를 반환합니다. 그렇지 않다면, 새로운 더 높은 보안 수준에서 해당 단계를 재시도합니다.
    Insufficient Authorization
    해당 단계에서 SecurityError를 반환합니다.
    Application Error
    GATT 절차가 쓰기(Write)이었다면, 해당 단계에서 InvalidModificationError를 반환합니다. 그렇지 않다면, NotSupportedError를 반환합니다.
    Read Not Permitted
    Write Not Permitted
    Request Not Supported
    Prepare Queue Full
    Insufficient Resources
    Unlikely Error
    그 외 모두
    해당 단계에서 NotSupportedError를 반환합니다.

7. UUID

typedef DOMString UUID;

UUID 문자열은 128비트 [RFC4122] UUID를 나타냅니다. valid UUID[ECMAScript] 정규식 /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/에 일치하는 문자열입니다. 즉, valid UUID는 소문자이며, Bluetooth 표준에 정의된 16비트 또는 32비트 약어를 사용하지 않습니다. 이 명세의 함수와 속성에서 반환되는 모든 UUID는 valid UUID이어야 합니다(MUST). 또한 이 명세의 어떤 함수가 UUID 타입의 매개변수나 UUID 속성을 포함하는 사전을 매개변수로 받을 때, 전달된 인수의 어떤 UUID 슬롯이라도 valid UUID가 아니면, 해당 함수는 거부된 프라미스TypeError와 함께 반환하고 다른 단계를 중단해야 합니다.

Note: 이 표준은 16비트 또는 32비트 Bluetooth UUID 별칭을 128비트 형태로 매핑하기 위한 BluetoothUUID.canonicalUUID(alias) 함수를 제공합니다.
Note: Bluetooth 장치는 비교 전에( Attribute Type에 서술됨) 16비트 및 32비트 UUID를 128비트 UUID로 변환해야 하지만, 모든 장치가 그렇게 하지는 않습니다. 이러한 장치와 상호운용하기 위해, UA가 장치로부터 어떤 형태(16, 32, 128비트)로 UUID를 받았다면, 그 UUID의 다른 별칭을 장치로 다시 보낼 때에도 동일한 형태를 사용하는 것이 좋습니다.

7.1. 표준화된 UUID

Bluetooth SIG는 서비스, 특성, 디스크립터 및 기타 엔터티를 식별하는 UUID 레지스트리를 [BLUETOOTH-ASSIGNED]에 유지합니다. 이 절은 스크립트가 해당 UUID를 이름으로 조회할 수 있는 방법을 제공하여, 각 애플리케이션에서 이를 반복해 포함할 필요가 없도록 합니다.

valid name[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. canonicalUUID(alias)가 호출되면, 16비트 또는 32비트 UUID 별칭 alias가 나타내는 128비트 UUID를 반환해야 합니다(MUST).

Note: 이 알고리즘은 "00000000-0000-1000-8000-00805f9b34fb"의 상위 32비트를 별칭의 비트로 대체하는 것으로 구성됩니다. 예를 들어, canonicalUUID(0xDEADBEEF)"deadbeef-0000-1000-8000-00805f9b34fb"를 반환합니다.

BluetoothServiceUUID는 16비트 및 32비트 UUID 별칭, valid UUID, 그리고 valid nameGATT 할당 서비스 키에서 나타내며, 또는 동등하게 BluetoothUUID.getService()가 예외를 던지지 않는 값들을 의미합니다.

BluetoothCharacteristicUUID는 16비트 및 32비트 UUID 별칭, valid UUID, valid nameGATT 할당 특성 키에서 나타내며, 또는 동등하게 BluetoothUUID.getCharacteristic()가 예외를 던지지 않는 값들을 의미합니다.

BluetoothDescriptorUUID는 16비트 및 32비트 UUID 별칭, valid UUID, valid nameGATT 할당 디스크립터 키에서 나타내며, 또는 동등하게 BluetoothUUID.getDescriptor()가 예외를 던지지 않는 값들을 의미합니다.

ResolveUUIDName(name, GATT assigned numbers)을 수행하기 위해, UA는 다음 단계를 수행해야 합니다:
  1. nameunsigned long이면, BluetoothUUID.canonicalUUID(name)를 반환하고 이 단계를 중단합니다.

  2. namevalid UUID이면, name을 반환하고 이 단계를 중단합니다.

  3. namevalid name이며 GATT assigned numbers에서 valid UUID에 매핑된다면, 그 할당 번호를 alias로 두고 BluetoothUUID.canonicalUUID(alias)를 반환합니다.

  4. 그 외의 경우, TypeError를 던집니다.

정적 메서드 BluetoothUUID. getService(name)가 호출되면, ResolveUUIDName(name, GATT 할당 서비스)를 반환해야 합니다(MUST).

정적 메서드 BluetoothUUID. getCharacteristic(name)가 호출되면, ResolveUUIDName(name, GATT 할당 특성)을 반환해야 합니다(MUST).

정적 메서드 BluetoothUUID. getDescriptor(name)가 호출되면, ResolveUUIDName(name, GATT 할당 디스크립터)를 반환해야 합니다(MUST).

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 할당 번호 파일은 https://github.com/WebBluetoothCG/registries 저장소에 있습니다.

이 명세는 이전에 Bluetooth SIG가 제공한 매핑 테이블을 사용해 이러한 사람이 읽기 쉬운 이름을 정의했습니다. 해당 테이블이 더 이상 유지되지 않는 것이 확인되자, 명세 내에 직접 매핑 테이블을 명시했습니다.
parsing the GATT assigned numbers의 결과는 URL url에서 가져온 데이터를 바탕으로, valid name에서 valid UUID로의 매핑(또는 오류)이며, 다음 알고리즘으로 생성됩니다:
  1. url을 가져오고, 본문을 UTF-8로 디코딩한 값을 contents로 둡니다.

  2. linescontents'\n' 기준으로 분할한 결과로 둡니다.

  3. result를 빈 맵으로 둡니다.

  4. lines의 각 line에 대해 다음 하위 단계를 수행합니다:

    1. line이 비어 있거나 첫 글자가 '#'이면, 다음 줄로 넘어갑니다.

    2. linevalid name, 공백(U+0020), 그리고 valid UUID로만 구성되어 있다면, 그 이름을 name, 그 UUID를 uuid로 둡니다.

    3. 그렇지 않으면, 오류를 반환하고 이 단계를 중단합니다.

    4. name이 이미 result에 있다면, 오류를 반환하고 이 단계를 중단합니다.

    5. resultname에서 uuid로의 매핑을 추가합니다.

  5. result를 반환합니다.

GATT assigned servicesparsing the GATT assigned numbers를 다음 위치에서 수행한 결과입니다: https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt. UA는 이 파일을 주기적으로 다시 가져와야 하지만, 빈도는 규정되지 않습니다.

GATT assigned characteristicsparsing the GATT assigned numbers를 다음 위치에서 수행한 결과입니다: https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_characteristics.txt. UA는 이 파일을 주기적으로 다시 가져와야 하지만, 빈도는 규정되지 않습니다.

GATT assigned descriptorsparsing the GATT assigned numbers를 다음 위치에서 수행한 결과입니다: https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_descriptors.txt. UA는 이 파일을 주기적으로 다시 가져와야 하지만, 빈도는 규정되지 않습니다.

8. 광고 데이터 필터

광고 데이터 필터는 제조사 데이터나 서비스 데이터를 기준으로 매칭하는 방법을 나타냅니다.

parse an advertising data filterstring input으로부터 수행하려면, 다음 단계를 실행합니다:
  1. wordsinputstrictly split으로 / 기준 분할한 결과로 둡니다.

  2. words의 길이가 2와 같지 않다면, 오류를 반환하고 단계를 중단합니다.

  3. words[0]의 길이가 words[1]의 길이와 같지 않다면, 오류를 반환하고 단계를 중단합니다.

  4. prefixDatawords[0]으로 둡니다.

  5. prefixMaskwords[1]으로 둡니다.

  6. prefixData 또는 prefixMaskascii lower hex digit 시퀀스가 아니라면, 오류를 반환합니다.

  7. prefixIndex0으로 둡니다.

  8. let dataList를 빈 리스트로 둡니다.

  9. let maskList를 빈 리스트로 둡니다.

  10. prefixData의 길이보다 prefixIndex가 작을 동안, 다음 하위 단계를 수행합니다:

    1. dataprefixData의 인덱스 prefixIndexprefixIndex + 1 위치 문자를 16진수 숫자로 해석한 결과로 둡니다.

    2. maskprefixMask의 인덱스 prefixIndexprefixIndex + 1 위치 문자를 16진수 숫자로 해석한 결과로 둡니다.

    3. dataListdata를 추가합니다.

    4. maskListmask를 추가합니다.

    5. prefixIndex|prefixIndex| + 2로 설정합니다.

  11. result를 새로운 BluetoothDataFilterInit 사전으로 둡니다.

  12. result[dataPrefix] 를 dataList로 생성한 Uint8Array로 설정합니다.

  13. result[mask] 를 maskList로 생성한 Uint8Array로 설정합니다.

  14. result를 반환합니다.

9. 블록리스트

이 명세는 웹사이트가 접근할 수 있는 GATT 속성 및 제조사 데이터를 제한하기 위해 https://github.com/WebBluetoothCG/registries 저장소의 블록리스트 파일에 의존합니다.

valid company identifier string은 길이가 0보다 크고 5보다 작은 ascii lower hex digit 시퀀스입니다. 공식 회사 식별자 목록은 Bluetooth Assigned Numbers 웹사이트에서 확인할 수 있습니다.

parsing the manufacturer data blocklist의 결과는 URL url에서 가져온 데이터를 바탕으로, Company Identifier Code에서 BluetoothDataFilterInit 리스트로의 맵(또는 오류)이며, 다음 알고리즘으로 생성됩니다:
  1. url을 가져오고, 본문을 UTF-8로 디코딩한 값을 contents로 둡니다.

  2. linescontents에 대해 구분자 '\n'split(separator, limit) 을 호출한 결과로 둡니다.

  3. result를 빈 맵으로 둡니다.

  4. lines의 각 line에 대해 다음 하위 단계를 수행합니다:

    1. line이 비어 있거나 첫 글자가 '#'이면, 다음 줄로 넘어갑니다.

    2. regExp를 'manufacturer\ ([0-9a-f]+)\ ([0-9a-f]+\/[0-9a-f]+)'로 생성한 RegExp 로 둡니다.

    3. matchResultline에 대해 regExp.exec(string) 을 호출한 결과로 두고, matchResultnull이거나 그 길이가 3과 같지 않다면 오류를 반환합니다.

    4. companyIdentifierStr를, matchResult[1]이 valid company identifier string인 경우 matchResult[1]로 두고, 그렇지 않으면 오류를 반환합니다.

    5. companyIdentifiercompanyIdentifierStr를 16진수 숫자로 해석한 결과로 둡니다.

    6. dataPrefixStrmatchResult[2]로 둡니다.

    7. companyIdentifierresult에 없다면, result[companyIdentifier]를 빈 리스트로 설정합니다.

    8. dataFilterdataPrefixStr에 대해 parsing an advertising data filter 를 수행한 결과(오류가 아닌 경우)로 두고, 그렇지 않으면 오류를 반환합니다.

    9. result[companyIdentifier]에 dataFilter를 추가합니다.

  5. result를 반환합니다.

parsing the gatt blocklist의 결과는 URL url에서 가져온 데이터를 바탕으로, valid UUID에서 토큰으로의 맵(또는 오류)이며, 다음 알고리즘으로 생성됩니다:
  1. url을 가져오고, 본문을 UTF-8로 디코딩한 값을 contents로 둡니다.

  2. linescontents'\n' 기준으로 분할한 결과로 둡니다.

  3. result를 빈 맵으로 둡니다.

  4. lines의 각 line에 대해 다음 하위 단계를 수행합니다:

    1. line이 비어 있거나 첫 글자가 '#'이면, 다음 줄로 넘어갑니다.

    2. linevalid UUID 하나만으로 구성되어 있다면, uuid를 그 UUID로, token을 "exclude"로 둡니다.

    3. linevalid UUID, 공백(U+0020), 그리고 "exclude-reads" 또는 "exclude-writes" 토큰 중 하나로 구성되어 있다면, uuid를 그 UUID로, token을 해당 토큰으로 둡니다.

    4. 그렇지 않으면, 오류를 반환하고 이 단계를 중단합니다.

    5. uuid가 이미 result에 있다면, 오류를 반환하고 이 단계를 중단합니다.

    6. resultuuid에서 token으로의 매핑을 추가합니다.

  5. result를 반환합니다.

GATT blocklistparsing the gatt blocklist를 다음 위치에서 수행한 결과입니다: https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt. Manufacturer Data blocklistparsing the manufacturer data blocklist를 다음 위치에서 수행한 결과입니다: https://github.com/WebBluetoothCG/registries/blob/master/manufacturer_data_blocklist.txt. UA는 블록리스트를 주기적으로 다시 가져와야 하지만, 빈도는 규정되지 않습니다.

UUIDblocklisted로 간주되며, 이는 GATT blocklist의 값이 오류이거나, 해당 UUID가 GATT blocklist에서 "exclude"로 매핑되는 경우입니다.

UUIDblocklisted for reads로 간주되며, 이는 GATT blocklist의 값이 오류이거나, 해당 UUID가 GATT blocklist에서 "exclude" 또는 "exclude-reads"로 매핑되는 경우입니다.

UUIDblocklisted for writes로 간주되며, 이는 GATT blocklist의 값이 오류이거나, 해당 UUID가 GATT blocklist에서 "exclude" 또는 "exclude-writes"로 매핑되는 경우입니다.

제조사 데이터 manufacturerData는 다음 단계가 blocked를 반환하면 blocklisted manufacturer data입니다:
  1. Manufacturer Data blocklist의 값이 오류라면, blocked를 반환합니다.

  2. manufacturerBlocklistManufacturer Data blocklist의 값으로 둡니다.

  3. companyIdentifiermanufacturerData의 회사 식별자로 둡니다.

  4. companyIdentifiermanufacturerBlocklist에 없다면, unblocked를 반환합니다.

  5. manufacturerBlocklist[companyIdentifier]의 각 dataFilter에 대해 다음 하위 단계를 수행합니다:

    1. manufacturerData의 광고 데이터가 matchesdataFilter와 일치하면, blocked를 반환합니다.

  6. unblocked를 반환합니다.

제조사 데이터 필터 manufacturerDataFilter는 다음 단계가 blocked를 반환하면 blocklisted manufacturer data filter 입니다:
  1. Manufacturer Data blocklist의 값이 오류라면, blocked를 반환합니다.

  2. manufacturerBlocklistManufacturer Data blocklist의 값으로 둡니다.

  3. companyIdentifiermanufacturerDataFilter["companyIdentifier"] 로 둡니다.

  4. companyIdentifiermanufacturerBlocklist에 없다면, unblocked를 반환합니다.

  5. manufacturerBlocklist[companyIdentifier]의 각 dataFilter에 대해 다음 하위 단계를 수행합니다:

    1. manufacturerDataFilterstrict subset으로 dataFilter의 진부분집합인 경우, blocked를 반환합니다.

  6. unblocked를 반환합니다.

[SecureContext]
partial interface Navigator {
  [SameObject]
  readonly attribute Bluetooth bluetooth;
};

Navigatorassociated Bluetooth를 가지며, 이는 Bluetooth 객체입니다. Navigator 객체가 생성될 때, 그 객체의 associated Bluetooth는 해당 Navigator 객체의 relevant realm에서 생성된 새로운 Bluetooth 객체로 설정되어야 합니다.

Navigatorbluetooth getter 단계는 thisassociated Bluetooth를 반환하는 것입니다.

11. 통합

11.1. Permissions Policy

이 명세는 policy-controlled feature를 정의하며, 토큰 "bluetooth"로 식별됩니다. 이는 bluetooth 속성이 노출하는 메서드들을 Navigator 객체에서 사용할 수 있는지를 제어합니다.

이 기능에 대한 기본 허용 목록["self"]입니다.

12. 자동화된 테스트

사용자 에이전트 자동화와 애플리케이션 테스트 목적을 위해, 이 문서는 [WebDriver-BiDi] 명세에 대한 확장을 정의합니다.

Web Bluetooth API와 그 확장 명세는 테스트 작성자에게 도전 과제를 제시합니다. 해당 인터페이스를 충분히 테스트하려면 예측 가능하게 응답하는 물리 하드웨어 장치가 필요하기 때문입니다. 이를 해결하기 위해 이 문서는 물리 장치 주변기기 및 광고처럼 동작하는 시뮬레이션된 주변기기와 광고를 정의하고 제어할 수 있는 여러 WebDriver-BiDi 확장 명령을 정의합니다. 이러한 시뮬레이션된 주변기기와 광고는 특정 속성을 가진 장치를 나타내며, 그 판독 값은 전적으로 사용자가 정의할 수 있습니다.

top-level traversablesimulated Bluetooth adapter를 가질 수 있으며, 이는 발견된 simulated Bluetooth devices 집합을 보유하고 Central과 같은 역할을 취할 수 있는 소프트웨어 정의 Bluetooth 어댑터입니다.

simulated Bluetooth adaptersimulated Bluetooth device mapping을 가지며, 이는 Bluetooth 주소 strings 에서 simulated Bluetooth devices로의 ordered map입니다.

simulated Bluetooth adapter는 현재 어댑터 상태를 설명하는 문자열 열거형인 adapter state를 가지며, 가능한 열거형 값은 다음과 같습니다:

simulated Bluetooth adapter는 어댑터가 Bluetooth Low Energy를 지원하는지를 나타내는 불리언인 low-energy supported state를 가집니다.

시뮬레이션된 Bluetooth 장치는 소프트웨어로 정의된 Bluetooth 장치로, 실제 장치처럼 동작하며, 시뮬레이션된 Bluetooth 어댑터에 연결될 수 있고, 제조사 고유 데이터서비스 UUID와 같은 속성을 가질 수 있으며, 시뮬레이션된 GATT 서비스 매핑을 가진다. 이 매핑은 Bluetooth 순서가 있는 맵으로, UUID 문자열과 시뮬레이션된 GATT 서비스를 대응시킨다.

simulated GATT service는 소프트웨어로 정의된 Service로, simulated Bluetooth device에 속하며, UUID 속성을 가지며, Bluetooth cache에 존재하는 것으로 알려져 있고, simulated GATT characteristic mapping을 갖습니다. 이는 Bluetooth UUID 문자열에서 simulated GATT characteristics로의 ordered map입니다.

simulated GATT characteristic은 소프트웨어로 정의된 Characteristic으로, simulated GATT service에 속하며, UUID 속성과 Characteristic Properties 속성을 가지며, Bluetooth cache에 존재하는 것으로 알려져 있고, simulated GATT descriptor mapping을 갖습니다. 이는 Bluetooth UUID 문자열에서 simulated GATT descriptors로의 ordered map입니다.

Simulated GATT characteristic propertiessimulated GATT characteristic에 속하는 소프트웨어 정의 Characteristic Properties이며, Bluetooth cache에 존재하는 것으로 알려져 있습니다.

simulated GATT descriptor는 소프트웨어로 정의된 Descriptor로, simulated GATT characteristic에 속하고, UUID 속성을 가지며, Bluetooth cache에 존재하는 것으로 알려져 있습니다.

CDDL 스니펫은 독립적인 프로그래밍 처리를 위해 "browsingContext.BrowsingContext" 대신 "text" 타입을 사용합니다. 현재는 다른 모듈을 참조할 수 없습니다.

12.1. 정의

bluetooth.BluetoothUuid = text;
bluetooth.BluetoothManufacturerData = { key: uint, data: tstr };
bluetooth.CharacteristicProperties = {
  ? broadcast: bool,
  ? read: bool,
  ? writeWithoutResponse: bool,
  ? write: bool,
  ? notify: bool,
  ? indicate: bool,
  ? authenticatedSignedWrites: bool,
  ? extendedProperties: bool
}
key
Company Identifier Code입니다.
data
제조사 데이터의 byte sequence이며, base64로 인코딩됩니다.

12.2. bluetooth 모듈

bluetooth 모듈에는 원격 엔드의 Bluetooth 동작을 관리하기 위한 명령이 포함됩니다.

12.2.1. 타입

12.2.1.1. bluetooth.RequestDevice 타입
bluetooth.RequestDevice = text

bluetooth.RequestDevice는 장치 요청 프롬프트에서 단일 장치를 식별하는 식별자입니다.

device prompttuple로, 문자열인 device prompt idset of devices(이는 set이며 BluetoothDevice 객체들의 집합)로 구성됩니다. 이는 사용자가 choose하여 Bluetooth device를 선택할 수 있는 프롬프트를 나타냅니다.

12.2.1.2. bluetooth.RequestDeviceInfo 타입
bluetooth.RequestDeviceInfo = {
   id: bluetooth.RequestDevice,
   name: text / null,
}

bluetooth.RequestDeviceInfo는 장치 요청 프롬프트의 단일 장치를 나타냅니다.

BluetoothDevice device가 주어졌을 때, serialize a device를 수행하려면:
  1. iddevice.id로 둡니다.

  2. namedevice.name으로 둡니다.

  3. bluetooth.RequestDeviceInfo 생성 규칙과 일치하는 map을 반환하되, "id"id, "name"name으로 설정합니다.

12.2.1.3. bluetooth.RequestDevicePrompt 타입
bluetooth.RequestDevicePrompt = text

bluetooth.RequestDevicePrompt는 단일 프롬프트의 식별자입니다.

원격 측은 map of navigables to device prompts를 가지며, 이는 키가 navigable ids이고 값이 device promptsmap입니다.

navigableIdpromptId가 주어졌을 때 get a prompt를 수행하려면:
  1. promptMapmap of navigables to device prompts로 둡니다.

  2. promptMap[navigableId]가 exist하지 않으면:

    1. errorerror code no such prompt와 함께 반환합니다.

  3. promptmap of navigables to device prompts[navigableId]로 둡니다.

  4. promptdevice prompt idpromptId와 다르면:

    1. errorerror code no such prompt와 함께 반환합니다.

  5. 데이터 prompt와 함께 success를 반환합니다.

device prompt promptdeviceId가 주어졌을 때 match a device in prompt를 수행하려면:
  1. promptset of devices 안의 각 device에 대해:

    1. device.iddeviceId이면, 데이터 device와 함께 success를 반환합니다.

  2. 그렇지 않으면:

    1. errorerror code no such device와 함께 반환합니다.

device prompt prompt가 주어졌을 때 serialize prompt devices를 수행하려면:
  1. devices를 빈 list로 둡니다.

  2. promptset of devices의 각 device에 대해 수행합니다.

    1. Appendserializing device의 결과를 devices에 추가합니다.

  3. devices를 반환합니다.

12.2.1.4. bluetooth.ScanRecord 타입
bluetooth.ScanRecord = {
  ? name: text,
  ? uuids: [ * bluetooth.BluetoothUuid ],
  ? appearance: number,
  ? manufacturerData: [ * bluetooth.BluetoothManufacturerData ],
}

bluetooth.ScanRecordBluetooth device가 전송한 광고 패킷의 데이터를 나타냅니다.

name
Bluetooth device의 로컬 이름 또는 그 접두사입니다.
uuids
이 스캔 레코드가 해당 Bluetooth device의 GATT 서버가 지원한다고 밝힌 서비스 UUID들을 나열합니다.
appearance
Appearance로, gap.appearance 특성에서 정의된 값 중 하나입니다.
manufacturerData
BluetoothManufacturerData의 리스트로, unsigned short Company Identifier Code에서 base64로 인코딩된 제조사 데이터 byte sequences로의 매핑입니다.

12.2.2. 오류

이 명세는 error codes의 집합을 WebDriver BiDi에서 다음의 추가 코드로 확장합니다:

no such device
알 수 없는 BluetoothDevice를 참조하려고 시도했습니다.
no such prompt
알 수 없는 device 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,
)
remote end stepscommand parameters가 주어졌을 때 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. promptIdparams["prompt"]로 둡니다.

  3. prompt를, contextIdpromptIdtrying하여 get a prompt한 결과로 둡니다.

  4. acceptcommand parametersaccept 필드 값으로 둡니다.

  5. accept가 true이면:

    1. deviceIdcommand parametersdevice 필드 값으로 둡니다.

    2. device를, promptdeviceId가 주어졌을 때 trying하여 match a device in prompt한 결과로 둡니다.

    3. deviceprompt를 승인합니다.

  6. 그렇지 않으면:

    1. prompt를 해제합니다.

  7. 데이터 null과 함께 success를 반환합니다.

local end는 다음 메시지를 보내 프롬프트를 해제할 수 있습니다:
{
  "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"
}
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. navigabletop-level traversable이 아니면, errorerror code invalid argument와 함께 반환합니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, 다음 단계를 수행합니다:

    1. params["leSupported"]가 exist하지 않으면, params["leSupported"]를 true로 설정합니다.

    2. simulatedBluetoothAdapter를 새로운 simulated Bluetooth adapter로 둡니다.

    3. simulatedBluetoothAdapterLE supported stateparams["leSupported"]로 설정합니다.

    4. simulatedBluetoothAdapteradapter stateparams["state"]로 설정합니다.

    5. navigablesimulated Bluetooth adaptersimulatedBluetoothAdapter로 설정합니다.

    6. 데이터 null과 함께 success를 반환합니다.

  6. simulatedBluetoothAdapter가 비어 있지 않으면, 다음 단계를 수행합니다:

    1. params["leSupported"]가 exists이면, errorerror code invalid argument와 함께 반환합니다.

    2. simulatedBluetoothAdapteradapter stateparams["state"]로 설정합니다.

    3. 데이터 null과 함께 success를 반환합니다.

local end는 다음 메시지를 보내 Bluetooth Low Energy를 지원하는 어댑터를 시뮬레이션할 수 있습니다:
{
  "method": "bluetooth.simulateAdapter",
  "params": {
    "context": "cxt-d03fdd81",
    "leSupported": true,
    "state": "powered-on",
  }
}
local end는 다음 메시지를 보내 기존 어댑터의 adapter state를 업데이트할 수 있습니다:
{
  "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
}
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. navigabletop-level traversable이 아니면, errorerror code invalid argument와 함께 반환합니다.

  4. navigablesimulated Bluetooth adapter를 비움으로 설정합니다.

  5. 데이터 null과 함께 success를 반환합니다.

local end는 다음 메시지를 보내 기존 시뮬레이션을 비활성화할 수 있습니다:
{
  "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 ]
}
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextId를 params["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. navigabletop-level traversable이 아니면, errorerror code invalid argument와 함께 반환합니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceAddressparams["address"]로 둡니다.

  7. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  8. deviceMapping[deviceAddress]가 exists이면, errorerror code invalid argument와 함께 반환합니다.

  9. simulatedBluetoothDevice를 새로운 simulated Bluetooth device로 둡니다.

  10. simulatedBluetoothDevice의 name을 params["name"]으로 설정합니다.

  11. simulatedBluetoothDevice의 address를 params["address"]로 설정합니다.

  12. simulatedBluetoothDevicemanufacturer specific dataparams["manufacturerData"]에 대해 수행한 forgiving-base64 decode의 출력으로 설정합니다.

  13. simulatedBluetoothDeviceservice UUIDsparams["knownServiceUuids"]로 설정합니다.

  14. deviceMapping[deviceAddress]을 simulatedBluetoothDevice로 설정합니다.

  15. 데이터 null과 함께 success를 반환합니다.

local end는 다음 메시지를 보내 사전 연결된 주변기기를 시뮬레이션할 수 있습니다:
{
  "method": "bluetooth.simulatePreconnectedPeripheral",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "name": "Some Device",
    "manufacturerData": [ { key: 17, data: "AP8BAX8=" } ],
    "knownServiceUuids": [
      "12345678-1234-5678-9abc-def123456789",
    ],
  }
}
12.2.3.5. bluetooth.simulateAdvertisement 명령
bluetooth.SimulateAdvertisement = (
   method: "bluetooth.simulateAdvertisement",
   params: bluetooth.SimulateAdvertisementParameters,
)
 
bluetooth.SimulateAdvertisementParameters = {
   context: text,
   scanEntry: bluetooth.SimulateAdvertisementScanEntryParameters
}
 
bluetooth.SimulateAdvertisementScanEntryParameters = {
   deviceAddress: text,
   rssi: number,
   scanRecord: bluetooth.ScanRecord
}
 
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. topLevelNavigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. topLevelNavigabletop-level traversable이 아니면, errorerror code invalid argument와 함께 반환합니다.

  4. scanEntryparams["scanEntry"]로 둡니다.

  5. deviceAddressscanEntry["deviceAddress"]로 둡니다.

  6. simulatedBluetoothAdaptertopLevelNavigablesimulated Bluetooth adapter로 둡니다.

  7. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  8. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  9. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다. 그렇지 않으면 simulatedDevice를 새로운 simulated Bluetooth device(주소는 deviceAddress)로 두고, deviceMapping[deviceAddress]를 simulatedDevice로 설정합니다.

  10. topLevelNavigable이 현재 scan for devices 알고리즘을 실행 중이면, 해당 알고리즘의 simulatedBluetoothDevices 변수에 simulatedDevice를 삽입합니다.

    다른 알고리즘의 변수에 데이터를 삽입하는 것은 명확히 정의되어 있지 않습니다. 구현과 일치하도록 하려면 scan for devices 알고리즘이 비동기 장치 검색을 정의할 필요가 있습니다.

  11. navigables를, topLevelNavigableactive documentinclusive descendant navigables로 둡니다.

  12. navigables의 각 navigable에 대해:

    1. documentnavigableactive document로 둡니다.

    2. Queue a taskdocumentrelevant settings objectresponsible event loop에 대기시켜 다음 하위 단계를 수행합니다:

      1. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

      2. simulatedDeviceInstance.[[watchAdvertisementsState]]not-watching이면, 이 하위 단계를 중단합니다.

      3. Fire an advertisementreceived eventscanEntry["scanRecord"]가 나타내는 광고 이벤트에 대해 simulatedDeviceInstance에서 발생시킵니다.

  13. 데이터 null과 함께 success를 반환합니다.

local end는 다음 메시지를 보내 장치 광고를 시뮬레이션할 수 있습니다:
{
  "method": "bluetooth.simulateAdvertisement",
  "params": {
    "context": "cxt-d03fdd81",
    "scanEntry": {
      "deviceAddress": "08:08:08:08:08:08",
      "rssi": -10,
      "scanRecord": {
        "name": "Heart Rate",
        "uuids": ["0000180d-0000-1000-8000-00805f9b34fb"],
        "manufacturerData": [ { key: 17, data: "AP8BAX8=" } ],
        "appearance": 1,
        "txPower": 1
      }
    }
  }
}
12.2.3.6. bluetooth.simulateGattConnectionResponse 명령
bluetooth.SimulateGattConnectionResponse = (
   method: "bluetooth.simulateGattConnectionResponse",
   params: bluetooth.SimulateGattConnectionResponseParameters,
)
 
bluetooth.SimulateGattConnectionResponseParameters = {
   context: text,
   address: text,
   code: uint
}
 
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  8. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  9. simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]"expected"이면, simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]params["code"]로 설정합니다.

  10. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

local end는 다음 메시지를 보내 성공( List of Error Codes에 따르면 오류 코드 0x00)에 해당하는 장치 gatt 연결 응답을 시뮬레이션할 수 있습니다:
{
  "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,
}
 
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  8. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  9. simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]"expected"이면, simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]0x15로 설정합니다.

    0x15List of Error Codes에 따르면 "Remote Device Terminated Connection due to Power Off"를 나타냅니다. 이는 Bluetooth 장치가 GATT 연결 시도에 응답할 수 없는 시나리오를 시뮬레이션합니다.
  10. 그렇지 않으면, clean up the disconnected device simulatedDeviceInstance를 수행합니다.

local end는 다음 메시지를 보내 장치 GATT 연결 해제를 시뮬레이션할 수 있습니다:
{
  "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",
}
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다.

  8. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  9. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  10. serviceMappingsimulatedDevicesimulated GATT service mapping으로 둡니다.

  11. uuidparams["uuid"]로 둡니다.

  12. params["type"]이 "add"이면:

    1. serviceMapping[uuid]가 exists이면, errorerror code invalid element state와 함께 반환합니다.

    2. simulatedGattService를 새로운 simulated GATT service로 둡니다.

    3. simulatedGattServiceUUIDuuid로 설정합니다.

    4. serviceMapping[uuid]을 simulatedGattService로 설정합니다.

    5. Create a BluetoothRemoteGATTService representing simulatedGattService 를 생성하고, 생성 결과인 Promise에 대해 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]simulatedGattService에서 해당 Promise로의 매핑을 추가합니다.

    6. 데이터 null과 함께 success를 반환합니다.

  13. params["type"]이 "remove"이면:

    1. serviceMapping[uuid]가 exists이면, simulatedGattServiceserviceMapping[uuid]로 둡니다.

    2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    3. simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]에서 simulatedGattService를 제거합니다.

    4. serviceMapping에서 uuid를 제거합니다.

    5. 데이터 null과 함께 success를 반환합니다.

  14. errorerror code invalid argument와 함께 반환합니다.

local end는 다음 메시지를 보내 GATT 서비스를 추가하는 시뮬레이션을 할 수 있습니다:
{
  "method": "bluetooth.simulateService",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "uuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "type": "add"
  }
}
local end는 다음 메시지를 보내 GATT 서비스를 제거하는 시뮬레이션을 할 수 있습니다:
{
  "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"
}
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다.

  8. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  9. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  10. serviceMappingsimulatedDevicesimulated GATT service mapping으로 둡니다.

  11. serviceUuidparams["serviceUuid"]로 둡니다.

  12. serviceMapping[serviceUuid]가 exists이면 simulatedServiceserviceMapping[serviceUuid]로 둡니다.

  13. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  14. characteristicMappingsimulatedServicesimulated GATT characteristic mapping으로 둡니다.

  15. characteristicUuidparams["characteristicUuid"]로 둡니다.

  16. params["type"]이 "add"이면:

    1. characteristicMapping[characteristicUuid]가 exists이면, errorerror code invalid element state와 함께 반환합니다.

    2. params["characteristicProperties"]가 exist하지 않으면, errorerror code invalid argument와 함께 반환합니다.

    3. simulatedGattCharacteristicProperties를 새로운 simulated GATT characteristic properties로 두고, 다음 단계를 수행합니다:

      1. propertiesparams["characteristicProperties"]로 둡니다.

      2. properties["broadcast"]가 exists이면, properties["broadcast"]가 true일 때 simulatedGattCharacteristicPropertiesBroadcast 비트를 설정합니다.

      3. properties["read"]가 exists이면, properties["read"]가 true일 때 simulatedGattCharacteristicPropertiesRead 비트를 설정합니다.

      4. properties["writeWithoutResponse"]가 exists이면, properties["writeWithoutResponse"]가 true일 때 simulatedGattCharacteristicPropertiesWrite Without Response 비트를 설정합니다.

      5. properties["write"]가 exists이면, properties["write"]가 true일 때 simulatedGattCharacteristicPropertiesWrite 비트를 설정합니다.

      6. properties["notify"]가 exists이면, properties["notify"]가 true일 때 simulatedGattCharacteristicPropertiesNotify 비트를 설정합니다.

      7. properties["indicate"]가 exists이면, properties["indicate"]가 true일 때 simulatedGattCharacteristicPropertiesIndicate 비트를 설정합니다.

      8. properties["authenticatedSignedWrites"]가 exists이면, properties["authenticatedSignedWrites"]가 true일 때 simulatedGattCharacteristicPropertiesAuthenticated Signed Writes 비트를 설정합니다.

      9. properties["extendedProperties"]가 exists이면, properties["extendedProperties"]가 true일 때 simulatedGattCharacteristicPropertiesExtended Properties 비트를 설정합니다.

    4. simulatedGattCharacteristic를 새로운 simulated GATT characteristic으로 둡니다.

    5. simulatedGattCharacteristicUUIDcharacteristicUuid로 설정합니다.

    6. simulatedGattCharacteristicCharacteristic PropertiessimulatedGattCharacteristicProperties로 설정합니다.

    7. characteristicMapping[characteristicUuid]을 simulatedGattCharacteristic로 설정합니다.

    8. Create a BluetoothRemoteGATTCharacteristic representing simulatedGattCharacteristic 를 생성하고, 생성된 Promise에 대해 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]simulatedGattCharacteristic에서 해당 Promise로의 매핑을 추가합니다.

    9. 데이터 null과 함께 success를 반환합니다.

  17. params["type"]이 "remove"이면:

    1. params["characteristicProperties"]가 exists이면, errorerror code invalid argument와 함께 반환합니다.

    2. characteristicMapping[characteristicUuid]가 exists이면, simulatedGattCharacteristiccharacteristicMapping[characteristicUuid]로 둡니다.

    3. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    4. simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]에서 simulatedGattCharacteristic를 제거합니다.

    5. characteristicUuidcharacteristicMapping에서 제거합니다.

    6. 데이터 null과 함께 success를 반환합니다.

  18. errorerror code invalid argument와 함께 반환합니다.

local end는 다음 메시지를 보내 읽기(read), 쓰기(write), 알림(notify) 속성을 가진 GATT 특성 추가를 시뮬레이션할 수 있습니다:
{
  "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"
  }
}
local end는 다음 메시지를 보내 GATT 특성 제거를 시뮬레이션할 수 있습니다:
{
  "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 ]
}
remote end steps는 명령 매개변수 params와 함께 다음과 같습니다:
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  8. serviceMappingsimulatedDevicesimulated GATT service mapping으로 둡니다.

  9. serviceUuidparams["serviceUuid"]로 둡니다.

  10. serviceMapping[serviceUuid]가 exists이면 simulatedServiceserviceMapping[serviceUuid]로 둡니다.

  11. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  12. characteristicMappingsimulatedServicesimulated GATT characteristic mapping으로 둡니다.

  13. characteristicUuidparams["characteristicUuid"]로 둡니다.

  14. characteristicMapping[characteristicUuid]가 exists이면 simulatedGattCharacteristiccharacteristicMapping[characteristicUuid]로 둡니다.

  15. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

  16. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  17. promisesimulatedDeviceInstance.[[context]].[[attributeInstanceMap]][simulatedGattCharacteristic]로 둡니다.

  18. Upon fulfillment of promise with characteristic, 다음 단계를 수행합니다:

    1. params["type"]이 read이면, 다음 단계를 수행합니다:

      1. characteristic.[[automatedCharacteristicReadResponse]]expected이면, characteristic.[[automatedCharacteristicReadResponse]]params["code"]로 설정하고, characteristic.[[automatedCharacteristicReadResponseData]]a copy of the bytes held by params["data"]로 설정합니다.

      2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    2. params["type"]이 write이면, 다음 단계를 수행합니다:

      1. characteristic.[[automatedCharacteristicWriteResponse]]expected이면, characteristic.[[automatedCharacteristicWriteResponse]]params["code"]로 설정합니다.

      2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    3. params["type"]이 subscribe-to-notifications이면, 다음 단계를 수행합니다:

      1. characteristic.[[automatedCharacteristicSubscribeToNotificationsResponse]]expected이면, characteristic.[[automatedCharacteristicSubscribeToNotificationsResponse]]params["code"]로 설정합니다.

      2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    4. params["type"]이 unsubscribe-from-notifications이면, 다음 단계를 수행합니다:

      1. characteristic.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]expected이면, characteristic.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]params["code"]로 설정합니다.

      2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    5. 그 외의 경우, errorerror code invalid argument와 함께 반환합니다.

local end는 특성 읽기 작업에 대한 데이터와 함께 성공 응답(Error Response에 따르면 오류 코드 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"
}
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다.

  8. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  9. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  10. serviceMappingsimulatedDevicesimulated GATT service mapping으로 둡니다.

  11. serviceUuidparams["serviceUuid"]로 둡니다.

  12. serviceMapping[serviceUuid]가 exists이면 simulatedServiceserviceMapping[serviceUuid]로 둡니다.

  13. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  14. characteristicMappingsimulatedServicesimulated GATT characteristic mapping으로 둡니다.

  15. characteristicUuidparams["characteristicUuid"]로 둡니다.

  16. characteristicMapping[characteristicUuid]가 exists이면 simulatedCharacteristiccharacteristicMapping[characteristicUuid]로 둡니다.

  17. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  18. descriptorMappingsimulatedCharacteristicsimulated GATT descriptor mapping으로 둡니다.

  19. descriptorUuidparams["descriptorUuid"]로 둡니다.

  20. params["type"]이 "add"이면:

    1. descriptorMapping[descriptorUuid]가 exists이면, errorerror code invalid element state와 함께 반환합니다.

    2. simulatedGattDescriptor를 새로운 simulated GATT descriptor로 둡니다.

    3. simulatedGattDescriptorUUIDdescriptorUuid로 설정합니다.

    4. descriptorMapping[descriptorUuid]을 simulatedGattDescriptor로 설정합니다.

    5. Create a BluetoothRemoteGATTDescriptor representing simulatedGattDescriptor 를 생성하고, 생성된 Promise에 대해 simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]simulatedGattDescriptor에서 해당 Promise로의 매핑을 추가합니다.

    6. 데이터 null과 함께 success를 반환합니다.

  21. params["type"]이 "remove"이면:

    1. descriptorMapping[descriptorUuid]가 exists이면, simulatedGattDescriptordescriptorMapping[descriptorUuid]로 둡니다.

    2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    3. simulatedDeviceInstance.[[context]].[[attributeInstanceMap]]에서 simulatedGattDescriptor를 제거합니다.

    4. descriptorUuiddescriptorMapping에서 제거합니다.

    5. 데이터 null과 함께 success를 반환합니다.

  22. errorerror code invalid argument와 함께 반환합니다.

local end는 다음 메시지를 보내 GATT 디스크립터 추가를 시뮬레이션할 수 있습니다:
{
  "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"
  }
}
local end는 다음 메시지를 보내 GATT 디스크립터 제거를 시뮬레이션할 수 있습니다:
{
  "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 ]
}
  1. contextIdparams["context"]로 둡니다.

  2. navigable을, contextIdtrying하여 get a navigable한 결과로 둡니다.

  3. deviceAddressparams["address"]로 둡니다.

  4. simulatedBluetoothAdapternavigablesimulated Bluetooth adapter로 둡니다.

  5. simulatedBluetoothAdapter가 비어 있으면, errorerror code invalid argument와 함께 반환합니다.

  6. deviceMappingsimulatedBluetoothAdaptersimulated Bluetooth device mapping으로 둡니다.

  7. deviceMapping[deviceAddress]가 exists이면 simulatedDevicedeviceMapping[deviceAddress]로 둡니다. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  8. serviceMappingsimulatedDevicesimulated GATT service mapping으로 둡니다.

  9. serviceUuidparams["serviceUuid"]로 둡니다.

  10. serviceMapping[serviceUuid]가 exists이면 simulatedServiceserviceMapping[serviceUuid]로 둡니다.

  11. 그렇지 않으면, errorerror code invalid argument와 함께 반환합니다.

  12. characteristicMappingsimulatedServicesimulated GATT characteristic mapping으로 둡니다.

  13. characteristicUuidparams["characteristicUuid"]로 둡니다.

  14. characteristicMapping[characteristicUuid]가 exists이면 simulatedCharacteristiccharacteristicMapping[characteristicUuid]로 둡니다.

  15. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

  16. descriptorMappingsimulatedCharacteristicsimulated GATT descriptor mapping으로 둡니다.

  17. descriptorUuidparams["descriptorUuid"]로 둡니다.

  18. descriptorMapping[descriptorUuid]가 exists이면 simulatedDescriptordescriptorMapping[descriptorUuid]로 둡니다.

  19. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

  20. simulatedDeviceInstance를, navigableactive windowassociated Navigatorassociated Bluetooth 내부에서 get the BluetoothDevice representing simulatedDevice의 결과로 둡니다.

  21. promisesimulatedDeviceInstance.[[context]].[[attributeInstanceMap]][simulatedDescriptor]로 둡니다.

  22. Upon fulfillment of promise with descriptor, 다음 단계를 수행합니다:

    1. params["type"]이 read이면, 다음 단계를 수행합니다:

      1. descriptor.[[automatedDescriptorReadResponse]]expected이면, descriptor.[[automatedDescriptorReadResponse]]params["code"]로 설정하고, descriptor.[[automatedDescriptorReadResponseData]]a copy of the bytes held by params["data"]로 설정합니다.

      2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    2. params["type"]이 write이면, 다음 단계를 수행합니다:

      1. characteristic.[[automatedDescriptorWriteResponse]]expected이면, characteristic.[[automatedDescriptorWriteResponse]]params["code"]로 설정합니다.

      2. 그렇지 않으면, errorerror code invalid element state와 함께 반환합니다.

    3. 그 외의 경우, errorerror code invalid argument와 함께 반환합니다.

local end는 디스크립터 읽기 작업에 대한 데이터와 함께 성공 응답(Error Response에 따르면 오류 코드 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],
}
navigable navigable, 문자열 promptId, 그리고 set 에 속한 Bluetooth devices devices가 주어졌을 때, prompt updated 이벤트를 트리거하려면 다음을 수행합니다:
  1. navigableIdnavigablenavigable id로 둡니다.

  2. promptdevice prompt (promptId, devices)로 둡니다.

  3. serialized devices를, promptserialize prompt devices를 수행한 결과로 둡니다.

  4. map of navigables to device prompts[navigableId]를 prompt로 설정합니다.

  5. paramsmap으로서 bluetooth.RequestDevicePromptUpdatedParameters 생성식과 일치하도록 만들고, context 필드를 navigableId, prompt 필드를 promptId, devices 필드를 serialized devices로 설정합니다.

  6. bodymap으로서 bluetooth.RequestDevicePromptUpdated 생성식과 일치하도록 만들고, params 필드를 params로 설정합니다.

  7. relatedNavigablesset으로서 navigable을 포함하도록 둡니다.

  8. 다음이 주어졌을 때, "bluetooth.requestDevicePromptUpdated" 및 relatedNavigables에 대해 set of sessions for which an event is enabled의 각 session에 대해:

    1. Emit an eventsessionbody로 수행합니다.

12.2.4.2. bluetooth.gattConnectionAttempted 이벤트
bluetooth.GattConnectionAttempted = (
   method: "bluetooth.gattConnectionAttempted",
   params: bluetooth.GattConnectionAttemptedParameters
)
 
bluetooth.GattConnectionAttemptedParameters = {
   context: text,
   address: text
}
navigable navigableBluetoothDevice device가 주어졌을 때, gatt connection attempted 이벤트를 트리거하려면:
  1. navigableIdnavigablenavigable id로 둡니다.

  2. paramsmap으로서 bluetooth.GattConnectionAttemptedParameters 생성식과 일치하도록 만들고, context 필드를 navigableId, address 필드를 device.[[representedDevice]]의 address로 설정합니다.

  3. bodymap으로서 bluetooth.GattConnectionAttempted 생성식과 일치하도록 만들고, params 필드를 params로 설정합니다.

  4. relatedNavigablesset으로서 navigable을 포함하도록 둡니다.

  5. 다음이 주어졌을 때, "bluetooth.gattEventGenerated" 및 relatedNavigables에 대해 set of sessions for which an event is enabled의 각 session에 대해:

    1. Emit an eventsessionbody로 수행합니다.

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 ]
}

trigger a simulated characteristic event 를 수행하기 위해, navigable navigable, BluetoothDevice device, simulated GATT characteristic characteristic, string type, 선택적 byte sequence bytes가 주어졌다고 하겠습니다:

  1. navigableIdnavigablenavigable id로 둡니다.

  2. paramsmap으로서 bluetooth.CharacteristicEventGeneratedParameters 생성식과 일치하도록 만들고 다음을 수행합니다:

    1. params["context"]를 navigableId로 설정합니다.

    2. params["address"]를 device.[[representedDevice]]의 address로 설정합니다.

    3. servicesimulated GATT servicecharacteristic을 포함하는 것으로 둡니다.

    4. params["serviceUuid"]를 serviceUUID로 설정합니다.

    5. params["characteristicUuid"]를 characteristicUUID로 설정합니다.

    6. params["type"]를 type으로 설정합니다.

    7. typewrite이면, 다음을 수행합니다:

      1. data를 빈 리스트로 둡니다.

      2. bytes의 각 byte에 대해:

        1. bytevaluedata에 추가합니다.

      3. params["data"]를 data로 설정합니다.

  3. bodymap으로서 bluetooth.CharacteristicEventGenerated 생성식과 일치하도록 만들고, params 필드를 params로 설정합니다.

  4. relatedNavigablesset으로서 navigable을 포함하도록 둡니다.

  5. 다음이 주어졌을 때, "bluetooth.characteristicEventGenerated" 및 relatedNavigables에 대해 set of sessions for which an event is enabled의 각 session에 대해:

    1. Emit an eventsessionbody로 수행합니다.

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 ]
}

trigger a simulated descriptor event 를 수행하기 위해, navigable navigable, BluetoothDevice device, simulated GATT descriptor descriptor, string type, 선택적 byte sequence bytes가 주어졌다고 하겠습니다:

  1. navigableIdnavigablenavigable id로 둡니다.

  2. paramsmap으로서 bluetooth.DescriptorEventGeneratedParameters 생성식과 일치하도록 만들고 다음을 수행합니다:

    1. params["context"]를 navigableId로 설정합니다.

    2. params["address"]를 device.[[representedDevice]]의 address로 설정합니다.

    3. characteristicsimulated GATT characteristicdescriptor를 포함하는 것으로 둡니다.

    4. servicesimulated GATT servicecharacteristic을 포함하는 것으로 둡니다.

    5. params["serviceUuid"]를 serviceUUID로 설정합니다.

    6. params["characteristicUuid"]를 characteristicUUID로 설정합니다.

    7. params["descriptorUuid"]를 descriptorUUID로 설정합니다.

    8. params["type"]를 type으로 설정합니다.

    9. typewrite이면, 다음을 수행합니다:

      1. data를 빈 리스트로 둡니다.

      2. bytes의 각 byte에 대해:

        1. bytevaluedata에 추가합니다.

      3. params["data"]를 data로 설정합니다.

  3. bodymap으로서 bluetooth.DescriptorEventGenerated 생성식과 일치하도록 만들고, params 필드를 params로 설정합니다.

  4. relatedNavigablesset으로서 navigable을 포함하도록 둡니다.

  5. 다음이 주어졌을 때, "bluetooth.descriptorEventGenerated" 및 relatedNavigables에 대해 set of sessions for which an event is enabled의 각 session에 대해:

    1. Emit an eventsessionbody로 수행합니다.

13. 용어 및 규약

이 명세는 몇 가지 관례와 다른 명세의 여러 용어를 사용합니다. 이 절은 그것들을 나열하고 해당 기본 정의로 연결합니다.

이 명세의 알고리즘이 이 명세 또는 다른 명세에서 정의된 이름을 사용할 때, 그 이름은 현재 실행 환경에서 그 이름에 가해진 어떤 변경도 무시하고, 초기 값으로 해석되어야 합니다. 예를 들어, requestDevice() 알고리즘이 Array.prototype.map.call(filter.services, BluetoothUUID.getService)를 호출하라고 말할 때, 이는 [ECMAScript]에 정의된 Array.prototype.map 알고리즘을 filter.servicesthis 매개변수로, § 7.1 Standardized UUIDs에 정의된 BluetoothUUID.getService 알고리즘을 callbackfn 매개변수로 적용해야 함을 의미합니다. 이는 window, Array, Array.prototype, Array.prototype.map, Function, Function.prototype, BluetoothUUID, BluetoothUUID.getService, 또는 다른 객체에 어떤 수정이 이루어졌는지와 무관합니다.

이 명세는 WebIDL의 FrozenArray와 유사한 읽기 전용 타입을 사용합니다.

[BLUETOOTH42]
  1. 아키텍처 및 용어 개요
    1. 일반 설명
      1. Bluetooth Low Energy 작동 개요 (defines advertising events)
    2. 통신 토폴로지 및 동작
      1. 동작 절차 및 모드
        1. BR/EDR 절차
          1. 조회(검색) 절차
            1. Extended Inquiry Response
  2. 코어 시스템 패키지 [BR/EDR 컨트롤러권]
    1. 오류 코드
      1. 오류 코드 개요
        1. List of Error Codes
    2. 호스트 컨트롤러 인터페이스 기능 명세
      1. HCI 명령 및 이벤트
        1. 정보 파라미터
          1. Read BD_ADDR Command
        2. 상태 파라미터
          1. Read RSSI Command
  3. 코어 시스템 패키지 [호스트권]
    1. 서비스 검색 프로토콜(SDP) 명세
      1. 개요
        1. Searching for Services
          1. UUID (defines UUID aliases and the algorithm to compute the 128-bit UUID represented by a UUID alias)
    2. 범용 액세스 프로파일
      1. 프로파일 개요
        1. 프로파일 역할
          1. LE 물리 전송 상의 역할
            1. Broadcaster Role
            2. Observer Role
            3. Peripheral Role
            4. Central Role
      2. 사용자 인터페이스 측면
        1. Bluetooth 매개변수의 표현
          1. Bluetooth Device Name (사용자 친화적 이름)
      3. 유휴 모드 절차 — BR/EDR 물리 전송
        1. Device Discovery Procedure
        2. BR/EDR Bonding Procedure
      4. 동작 모드 및 절차 — LE 물리 전송
        1. 브로드캐스트 모드 및 관찰 절차
          1. Observation Procedure
        2. 검색 모드 및 절차
          1. General Discovery Procedure
          2. Name Discovery Procedure
        3. 연결 모드 및 절차
        4. 페어링 모드 및 절차
          1. LE Bonding Procedure
      5. 보안 측면 — LE 물리 전송
        1. Privacy Feature
        2. Random Device Address
          1. Static Address
          2. Private address
            1. Resolvable Private Address Resolution Procedure
      6. Advertising Data 및 스캔 응답 데이터 형식 (defines AD structure)
      7. Bluetooth 장치 요구사항
        1. Bluetooth Device Address (defines BD_ADDR)
          1. Bluetooth 장치 주소 유형
            1. Public Bluetooth Address
      8. 정의 (defines bond)
    3. 속성 프로토콜(ATT)
      1. 프로토콜 요구사항
        1. 기본 개념
          1. Attribute Type
          2. Attribute Handle
          3. Long Attribute Values
        2. Attribute Protocol Pdus
          1. 오류 처리
            1. Error Response
    4. Generic Attribute Profile (GATT)
      1. 프로파일 개요
        1. 구성 및 역할 (defines GATT ClientGATT Server)
        2. Profile Fundamentals, ATT Bearer를 정의
        3. 속성 프로토콜
          1. Attribute Caching
        4. GATT Profile Hierarchy
          1. Service
          2. Included Services
          3. Characteristic
      2. Service Interoperability Requirements
        1. Service Definition
        2. 특성 정의
          1. 특성 선언
            1. Characteristic Properties
          2. 특성 Descriptor 선언
            1. Characteristic Extended Properties
            2. Client Characteristic Configuration
      3. GATT 기능 요구사항 — GATT procedures를 정의.
        1. 서버 구성
          1. Exchange MTU
        2. Primary Service Discovery
          1. 모든 기본 서비스 검색
          2. Discover Primary Service by Service UUID
        3. Relationship Discovery
          1. 포함된 서비스 찾기
        4. Characteristic Discovery
          1. 서비스의 모든 특성 검색
          2. Discover Characteristics by UUID
        5. Characteristic Descriptor Discovery
          1. Discover All Characteristic Descriptors
        6. Characteristic Value Read
        7. Characteristic Value Write
          1. Write Without Response
          2. Write Characteristic Value
        8. Characteristic Value Notification
        9. Characteristic Value Indications
        10. Characteristic Descriptors
          1. Read Characteristic Descriptors
          2. Read Long Characteristic Descriptors
          3. Write Characteristic Descriptors
          4. Write Long Characteristic Descriptors
        11. Procedure Timeouts
      4. GAP Interoperability Requirements
        1. BR/EDR GAP 상호운용성 요구사항
          1. 연결 설정
        2. LE GAP 상호운용성 요구사항
          1. 연결 설정
      5. 정의된 GATT 서비스
        1. Service Changed
    5. 보안 관리자 명세
      1. 보안 관리자
        1. Bluetooth Low Energy에서의 보안
          1. Definition of Keys and Values, 다음을 정의함: Identity Resolving Key (IRK)
  4. 코어 시스템 패키지 [저전력 컨트롤러권]
    1. 링크 계층 명세
      1. 일반 설명
        1. 장치 주소
          1. Public Device Address
          2. Random Device Address
            1. Static Device Address
      2. 무선 인터페이스 프로토콜
        1. 비연결 상태
          1. 스캐닝 상태
            1. Passive Scanning
[BLUETOOTH-SUPPLEMENT6]
  1. 데이터 타입 명세
    1. 데이터 타입 정의 및 형식
      1. Service UUID Data Type
      2. Local Name Data Type
      3. Flags Data Type (defines the Discoverable Mode flags)
      4. Manufacturer Specific Data
      5. TX Power Level
      6. Service Data
      7. Appearance

적합성

문서 규약

적합성 요구사항은 설명적 서술과 RFC 2119 용어의 조합으로 표현됩니다. 이 문서의 규범 부분에서 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” 키워드는 RFC 2119에 설명된 대로 해석되어야 합니다. 다만 가독성을 위해, 이 명세에서는 이러한 단어들이 모두 대문자로 표기되지 않을 수 있습니다.

이 명세의 모든 텍스트는 비규범으로 명시된 절, 예시, 주석을 제외하고 규범적입니다. [RFC2119]

이 명세에서 예시는 “for example”이라는 문구로 소개되거나, 규범 텍스트와 구분되어 class="example"로 표시됩니다. 예시는 다음과 같습니다:

이는 정보 목적의 예시입니다.

정보성 주석은 “Note”로 시작하며, 규범 텍스트와 구분되어 class="note"로 표시됩니다. 예시는 다음과 같습니다:

Note, 이는 정보성 주석입니다.

색인

이 명세에서 정의된 용어

참조로 정의된 용어

참고 문헌

규범 참조

[BLUETOOTH-ASSIGNED]
Assigned Numbers. Living Standard. URL: https://www.bluetooth.com/specifications/assigned-numbers/
[BLUETOOTH-SUPPLEMENT6]
Supplement to the Bluetooth Core Specification Version 6. 14 July 2015. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=302735
[BLUETOOTH42]
BLUETOOTH SPECIFICATION Version 4.2. 2 December 2014. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMAScript]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/
[FINGERPRINTING-GUIDANCE]
Nick Doty; Tom Ritter. Mitigating Browser Fingerprinting in Web Specifications. URL: https://w3c.github.io/fingerprinting-guidance/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 29 October 2013. REC. URL: https://www.w3.org/TR/page-visibility/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. Permissions. URL: https://w3c.github.io/permissions/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC4122]
P. Leach; M. Mealling; R. Salz. A Universally Unique IDentifier (UUID) URN Namespace. July 2005. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc4122
[RFC8610]
H. Birkholz; C. Vigano; C. Bormann. Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures. June 2019. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8610
[WEBDRIVER-BIDI]
James Graham; Alex Rudenko; Maksim Sadym. WebDriver BiDi. URL: https://w3c.github.io/webdriver-bidi/
[WEBDRIVER1]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBDRIVER2]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBHID]
WebHID API. Draft Community Group Report. URL: https://wicg.github.io/webhid/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

정보성 참조

[CSP3]
Mike West; Antonio Sartori. Content Security Policy Level 3. URL: https://w3c.github.io/webappsec-csp/

IDL 색인

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;

dictionary BluetoothPermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
  // These match RequestDeviceOptions.
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};

dictionary AllowedBluetoothDevice {
  required DOMString deviceId;
  required boolean mayUseGATT;
  // An allowedServices of "all" means all services are allowed.
  required (DOMString or sequence<UUID>) allowedServices;
  required sequence<unsigned short> allowedManufacturerData;
};
dictionary BluetoothPermissionStorage {
  required sequence<AllowedBluetoothDevice> allowedDevices;
};

[Exposed=Window]
interface BluetoothPermissionResult : PermissionStatus {
  attribute FrozenArray<BluetoothDevice> devices;
};

[
  Exposed=Window,
  SecureContext
]
interface ValueEvent : Event {
  constructor(DOMString type, optional ValueEventInit initDict = {});
  readonly attribute any value;
};

dictionary ValueEventInit : EventInit {
  any value = null;
};

[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;
};

[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;
};

[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);
};

[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;

[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;

[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;
};

[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);
};

[SecureContext]
interface mixin CharacteristicEventHandlers {
  attribute EventHandler oncharacteristicvaluechanged;
};

[SecureContext]
interface mixin BluetoothDeviceEventHandlers {
  attribute EventHandler onadvertisementreceived;
  attribute EventHandler ongattserverdisconnected;
};

[SecureContext]
interface mixin ServiceEventHandlers {
  attribute EventHandler onserviceadded;
  attribute EventHandler onservicechanged;
  attribute EventHandler onserviceremoved;
};

typedef DOMString UUID;

[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;

[SecureContext]
partial interface Navigator {
  [SameObject]
  readonly attribute Bluetooth bluetooth;
};

CDDL 색인

이슈 색인

§ 3 Privacy considerations 섹션을 참조하세요. [Issue #575]
실제로는 프롬프트가 열려 있는 동안 장치 목록이 동적으로 업데이트됩니다. 현재 명세 텍스트는 이를 반영하지 않지만, 이 이벤트는 동일한 promptId 및 최신 장치 목록과 함께 여러 번 발생할 수 있습니다. 참조: https://github.com/WebBluetoothCG/web-bluetooth/issues/621.
TODO: 시간 값을 확정해야 합니다.
비동기 장치 검색을 지원합니다.
passive scanningPrivacy Feature는 모두 고유하고 변경 불가능한 장치 ID가 유출되는 것을 방지합니다. UA가 둘 중 하나를 사용하도록 요구해야 하지만, 어떤 OS API도 이를 노출하지 않는 것으로 보입니다. 또한 Bluetooth는 Central 장치가 Observation Procedure를 지원할 것을 요구하지 않으므로 passive scanning을 사용하기 어렵게 만듭니다.
모든 형태의 BR/EDR 조회/검색은 고유하고 변경 불가능한 장치 주소가 유출되는 것으로 보입니다.
흥미로운 장치가 범위 내로 들어올 때 사이트가 이벤트 수신을 등록할 수 있는 방법이 필요합니다.
이러한 일반 이벤트 타입은 여기보다는 [HTML] 또는 [DOM]에 속합니다.
구현에서는 이 NetworkError를 피할 수 있을지 모르지만, 당분간은 사이트가 이 API 사용을 직렬화하고 실패한 작업을 다시 시도할 수 있는 방법을 사용자에게 제공해야 합니다. [Issue #188]
구현에서는 이 NetworkError를 피할 수 있을지 모르지만, 당분간은 사이트가 이 API 사용을 직렬화하고/또는 사용자가 실패한 작업을 다시 시도할 수 있는 방법을 제공해야 합니다. [Issue #188]
구현에서는 이 NetworkError를 피할 수 있을지 모르지만, 당분간은 사이트가 이 API 사용을 직렬화하고 실패한 작업을 다시 시도할 수 있는 방법을 사용자에게 제공해야 합니다. [Issue #188]
이 메서드는 하위 호환성만을 위한 것입니다. 새로운 구현에서는 이 메서드를 구현하지 마십시오. [Issue #238]
구현에서는 이 NetworkError를 피할 수 있을지 모르지만, 현재로서는 사이트가 이 API 사용을 직렬화하고/또는 사용자가 실패한 작업을 다시 시도할 수 있는 방법을 제공해야 합니다. [Issue #188]
Characteristic Extended Properties가 특정 Characteristic에 대해 확장 속성이 불변인지 명확하지 않습니다. 불변이라면, UA가 이를 캐시하는 것이 허용되어야 합니다.
구현에서는 이 NetworkError를 피할 수 있을지 모르지만, 당분간은 사이트가 이 API 사용을 직렬화하고 실패한 작업을 다시 시도할 수 있는 방법을 사용자에게 제공해야 합니다. [Issue #188]
구현에서는 이 NetworkError를 피할 수 있을지 모르지만, 당분간은 사이트가 이 API 사용을 직렬화하고 실패한 작업을 다시 시도할 수 있는 방법을 사용자에게 제공해야 합니다. [Issue #188]
CDDL 스니펫은 CDDL 스니펫의 독립적인 프로그램 처리(가공)를 가능하게 하기 위해 "browsingContext.BrowsingContext" 대신 "text" 타입을 사용합니다. 현재로서는 다른 모듈을 참조할 수 없습니다.
다른 알고리즘에서 변수로 데이터를 삽입하는 것은 잘 정의되어 있지 않습니다. 구현과 일치시키기 위해 scan for devices 알고리즘은 비동기 장치 검색을 정의할 필요가 있습니다.
MDN

Bluetooth/availabilitychanged_event

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for AndroidNoneAndroid WebView?Samsung Internet?Opera Mobile?
MDN

Bluetooth/availabilitychanged_event

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for AndroidNoneAndroid WebView?Samsung Internet?Opera Mobile?
MDN

Bluetooth/getAvailability

In only one current engine.

FirefoxNoneSafariNoneChrome78+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

Bluetooth/getDevices

In only one current engine.

FirefoxNoneSafariNoneChrome🔰 85+
Opera?Edge🔰 85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Bluetooth/requestDevice

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

Bluetooth

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/authenticatedSignedWrites

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/broadcast

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/indicate

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/notify

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/read

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/reliableWrite

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/writableAuxiliaries

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/write

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/writeWithoutResponse

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice/gatt

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice/id

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice/name

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/getDescriptor

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/getDescriptors

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/properties

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/readValue

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/service

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/startNotifications

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/stopNotifications

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/uuid

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/value

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/writeValueWithoutResponse

In only one current engine.

FirefoxNoneSafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/writeValueWithResponse

In only one current engine.

FirefoxNoneSafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTDescriptor/characteristic

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/readValue

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/uuid

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/value

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/writeValue

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android57+Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTServer/connect

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/connected

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/device

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/disconnect

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/getPrimaryService

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/getPrimaryServices

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/device

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/getCharacteristic

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/getCharacteristics

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/isPrimary

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/uuid

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/canonicalUUID_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/getCharacteristic_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/getDescriptor_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/getService_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?