@fww_123/uni-ble-scanner 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factory.d.ts +6 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +177 -1
- package/dist/index.js +178 -0
- package/dist/platforms/web-scanner.d.ts +35 -0
- package/dist/platforms/web-scanner.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/factory.ts +23 -4
- package/src/index.ts +1 -0
- package/src/platforms/web-scanner.ts +177 -0
- package/src/types/web-bluetooth.d.ts +103 -0
package/dist/factory.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { getPlatform, isApp } from './utils/platform';
|
|
|
3
3
|
/**
|
|
4
4
|
* 扫描器类型
|
|
5
5
|
*/
|
|
6
|
-
export type ScannerType = 'auto' | 'uniapp' | 'native';
|
|
6
|
+
export type ScannerType = 'auto' | 'uniapp' | 'native' | 'web';
|
|
7
7
|
/**
|
|
8
8
|
* 创建扫描器的选项
|
|
9
9
|
*/
|
|
@@ -19,6 +19,11 @@ export interface CreateScannerOptions {
|
|
|
19
19
|
* @returns 蓝牙扫描器实例
|
|
20
20
|
*/
|
|
21
21
|
export declare function createScanner(options?: CreateScannerOptions): IBLEScanner;
|
|
22
|
+
/**
|
|
23
|
+
* 创建 Web 扫描器
|
|
24
|
+
* 使用 Web Bluetooth API,适用于浏览器环境
|
|
25
|
+
*/
|
|
26
|
+
export declare function createWebScanner(platformConfig?: PlatformConfig): IBLEScanner;
|
|
22
27
|
/**
|
|
23
28
|
* 创建 UniApp 扫描器
|
|
24
29
|
* 使用 UniApp 标准蓝牙 API,兼容所有平台
|
package/dist/factory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAMhE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,aAAa;IACb,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,WAAW,CAqD7E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,WAAW,CAE7E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,WAAW,CAEhF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,WAAW,CAEhF;AAED;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AAEjC;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAc9C;AAED;;GAEG;AACH,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { UniAppScanner } from './platforms/uniapp-scanner';
|
|
|
10
10
|
export { AndroidNativeScanner } from './platforms/android-native';
|
|
11
11
|
export { IOSNativeScanner } from './platforms/ios-native';
|
|
12
12
|
export { HarmonyNativeScanner } from './platforms/harmony-native';
|
|
13
|
+
export { WebScanner, isWebBluetoothSupported } from './platforms/web-scanner';
|
|
13
14
|
import { createScanner } from './factory';
|
|
14
15
|
export default createScanner;
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,cAAc,EACd,YAAY,EACZ,oBAAoB,GACrB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,KAAK,GACN,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGjE,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,SAAS,GACV,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG3E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAG/D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,cAAc,EACd,YAAY,EACZ,oBAAoB,GACrB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,KAAK,GACN,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGjE,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,SAAS,GACV,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG3E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAG/D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,eAAe,aAAa,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1721,6 +1721,174 @@ class HarmonyNativeScanner extends BaseScanner {
|
|
|
1721
1721
|
}
|
|
1722
1722
|
}
|
|
1723
1723
|
|
|
1724
|
+
/**
|
|
1725
|
+
* Web 浏览器蓝牙扫描器
|
|
1726
|
+
* 使用 Web Bluetooth API
|
|
1727
|
+
*/
|
|
1728
|
+
class WebScanner extends BaseScanner {
|
|
1729
|
+
constructor() {
|
|
1730
|
+
super(...arguments);
|
|
1731
|
+
this.device = null;
|
|
1732
|
+
this.server = null;
|
|
1733
|
+
}
|
|
1734
|
+
getPlatform() {
|
|
1735
|
+
return Platform.UNKNOWN;
|
|
1736
|
+
}
|
|
1737
|
+
init() {
|
|
1738
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1739
|
+
return new Promise((resolve, reject) => {
|
|
1740
|
+
// 检查浏览器是否支持 Web Bluetooth
|
|
1741
|
+
if (!navigator.bluetooth) {
|
|
1742
|
+
reject(createError(ErrorCodes.UNSUPPORTED_PLATFORM, '当前浏览器不支持 Web Bluetooth API,请使用 Chrome、Edge 或 Opera'));
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
this.initialized = true;
|
|
1746
|
+
resolve();
|
|
1747
|
+
});
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
startScanInternal() {
|
|
1751
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1752
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
1753
|
+
try {
|
|
1754
|
+
// Web Bluetooth 使用 requestDevice 而不是扫描
|
|
1755
|
+
// 这会弹出浏览器的选择设备对话框
|
|
1756
|
+
const options = {
|
|
1757
|
+
acceptAllDevices: true,
|
|
1758
|
+
};
|
|
1759
|
+
// 添加服务过滤
|
|
1760
|
+
if (this.options.services && this.options.services.length > 0) {
|
|
1761
|
+
options.filters = this.options.services.map(uuid => ({
|
|
1762
|
+
services: [uuid],
|
|
1763
|
+
}));
|
|
1764
|
+
}
|
|
1765
|
+
else {
|
|
1766
|
+
options.acceptAllDevices = true;
|
|
1767
|
+
}
|
|
1768
|
+
// 请求设备(浏览器会弹出选择框)
|
|
1769
|
+
this.device = yield navigator.bluetooth.requestDevice(options);
|
|
1770
|
+
// 监听设备广告(如果支持)
|
|
1771
|
+
if (this.device.watchAdvertisements) {
|
|
1772
|
+
this.device.addEventListener('advertisementreceived', (event) => {
|
|
1773
|
+
this.handleDeviceFound({
|
|
1774
|
+
deviceId: this.device.id,
|
|
1775
|
+
name: this.device.name,
|
|
1776
|
+
RSSI: event.rssi || -50,
|
|
1777
|
+
advertisData: event.manufacturerData,
|
|
1778
|
+
});
|
|
1779
|
+
});
|
|
1780
|
+
yield this.device.watchAdvertisements();
|
|
1781
|
+
}
|
|
1782
|
+
else {
|
|
1783
|
+
// 如果不支持广告监听,直接返回设备信息
|
|
1784
|
+
this.handleDeviceFound({
|
|
1785
|
+
deviceId: this.device.id,
|
|
1786
|
+
name: this.device.name,
|
|
1787
|
+
RSSI: -50, // 默认值
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
resolve();
|
|
1791
|
+
}
|
|
1792
|
+
catch (error) {
|
|
1793
|
+
if (error.name === 'NotFoundError') {
|
|
1794
|
+
reject(Errors.scanFailed('用户取消了设备选择'));
|
|
1795
|
+
}
|
|
1796
|
+
else {
|
|
1797
|
+
reject(handlePlatformError(error, 'web'));
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}));
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
stopScanInternal() {
|
|
1804
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1805
|
+
// Web Bluetooth 没有明确的停止扫描方法
|
|
1806
|
+
// 设备选择后扫描就结束了
|
|
1807
|
+
if (this.device && this.device.unwatchAdvertisements) {
|
|
1808
|
+
yield this.device.unwatchAdvertisements();
|
|
1809
|
+
}
|
|
1810
|
+
return Promise.resolve();
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
checkPermissions() {
|
|
1814
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1815
|
+
// Web Bluetooth 权限由浏览器自动管理
|
|
1816
|
+
// 通过用户手势触发 requestDevice 时会自动请求权限
|
|
1817
|
+
return true;
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
requestPermissions() {
|
|
1821
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1822
|
+
// Web Bluetooth 不需要显式请求权限
|
|
1823
|
+
return true;
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
onAdapterStateChange(callback) {
|
|
1827
|
+
this.adapterStateListeners.push(callback);
|
|
1828
|
+
// Web Bluetooth 没有适配器状态变化事件
|
|
1829
|
+
// 直接返回当前状态
|
|
1830
|
+
callback({
|
|
1831
|
+
available: !!navigator.bluetooth,
|
|
1832
|
+
discovering: this.state === 'scanning',
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
destroy() {
|
|
1836
|
+
super.destroy();
|
|
1837
|
+
this.device = null;
|
|
1838
|
+
this.server = null;
|
|
1839
|
+
}
|
|
1840
|
+
/**
|
|
1841
|
+
* 连接到设备(Web Bluetooth 特有)
|
|
1842
|
+
*/
|
|
1843
|
+
connect() {
|
|
1844
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1845
|
+
var _a;
|
|
1846
|
+
if (!this.device) {
|
|
1847
|
+
throw Errors.notInitialized();
|
|
1848
|
+
}
|
|
1849
|
+
try {
|
|
1850
|
+
this.server = (yield ((_a = this.device.gatt) === null || _a === void 0 ? void 0 : _a.connect())) || null;
|
|
1851
|
+
return this.server;
|
|
1852
|
+
}
|
|
1853
|
+
catch (error) {
|
|
1854
|
+
throw handlePlatformError(error, 'web');
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* 断开连接(Web Bluetooth 特有)
|
|
1860
|
+
*/
|
|
1861
|
+
disconnect() {
|
|
1862
|
+
var _a;
|
|
1863
|
+
if (this.device && ((_a = this.device.gatt) === null || _a === void 0 ? void 0 : _a.connected)) {
|
|
1864
|
+
this.device.gatt.disconnect();
|
|
1865
|
+
}
|
|
1866
|
+
this.server = null;
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* 获取已连接的服务(Web Bluetooth 特有)
|
|
1870
|
+
*/
|
|
1871
|
+
getServices() {
|
|
1872
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1873
|
+
if (!this.server) {
|
|
1874
|
+
throw Errors.notInitialized();
|
|
1875
|
+
}
|
|
1876
|
+
try {
|
|
1877
|
+
return yield this.server.getPrimaryServices();
|
|
1878
|
+
}
|
|
1879
|
+
catch (error) {
|
|
1880
|
+
throw handlePlatformError(error, 'web');
|
|
1881
|
+
}
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* 检查浏览器是否支持 Web Bluetooth
|
|
1887
|
+
*/
|
|
1888
|
+
function isWebBluetoothSupported() {
|
|
1889
|
+
return 'bluetooth' in navigator && typeof navigator.bluetooth.requestDevice === 'function';
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1724
1892
|
/**
|
|
1725
1893
|
* 创建蓝牙扫描器
|
|
1726
1894
|
* @param options 创建选项
|
|
@@ -1730,6 +1898,14 @@ function createScanner(options = {}) {
|
|
|
1730
1898
|
const { type = 'auto', platformConfig = {} } = options;
|
|
1731
1899
|
const platform = getPlatform();
|
|
1732
1900
|
const app = isApp();
|
|
1901
|
+
// 检测是否在浏览器环境
|
|
1902
|
+
const isWeb = typeof window !== 'undefined' && !app;
|
|
1903
|
+
// 如果是 Web 环境或指定使用 Web 扫描器
|
|
1904
|
+
if (type === 'web' || (type === 'auto' && isWeb)) {
|
|
1905
|
+
const webScanner = new WebScanner();
|
|
1906
|
+
Object.assign(webScanner, { platformConfig });
|
|
1907
|
+
return webScanner;
|
|
1908
|
+
}
|
|
1733
1909
|
// 根据类型和平台选择合适的扫描器
|
|
1734
1910
|
if (type === 'uniapp' || (type === 'auto' && !app)) {
|
|
1735
1911
|
// 使用 UniApp 标准 API
|
|
@@ -1788,4 +1964,4 @@ function isBluetoothSupported() {
|
|
|
1788
1964
|
|
|
1789
1965
|
// 导出枚举
|
|
1790
1966
|
|
|
1791
|
-
export { AndroidNativeScanner, BaseScanner, ErrorCodes, Errors, HarmonyNativeScanner, IOSNativeScanner, Platform, ScanState, UniAppScanner, arrayBufferToBase64, base64ToArrayBuffer, checkPermissions, createError, createNativeScanner, createScanner, createUniAppScanner, createScanner as default, formatUUID, getPlatform, getPlatformName, isApp, isBluetoothSupported, isPlatform, matchUUID, parseAdvertisementData, requestPermissions };
|
|
1967
|
+
export { AndroidNativeScanner, BaseScanner, ErrorCodes, Errors, HarmonyNativeScanner, IOSNativeScanner, Platform, ScanState, UniAppScanner, WebScanner, arrayBufferToBase64, base64ToArrayBuffer, checkPermissions, createError, createNativeScanner, createScanner, createUniAppScanner, createScanner as default, formatUUID, getPlatform, getPlatformName, isApp, isBluetoothSupported, isPlatform, isWebBluetoothSupported, matchUUID, parseAdvertisementData, requestPermissions };
|
package/dist/index.js
CHANGED
|
@@ -1725,6 +1725,174 @@ class HarmonyNativeScanner extends BaseScanner {
|
|
|
1725
1725
|
}
|
|
1726
1726
|
}
|
|
1727
1727
|
|
|
1728
|
+
/**
|
|
1729
|
+
* Web 浏览器蓝牙扫描器
|
|
1730
|
+
* 使用 Web Bluetooth API
|
|
1731
|
+
*/
|
|
1732
|
+
class WebScanner extends BaseScanner {
|
|
1733
|
+
constructor() {
|
|
1734
|
+
super(...arguments);
|
|
1735
|
+
this.device = null;
|
|
1736
|
+
this.server = null;
|
|
1737
|
+
}
|
|
1738
|
+
getPlatform() {
|
|
1739
|
+
return exports.Platform.UNKNOWN;
|
|
1740
|
+
}
|
|
1741
|
+
init() {
|
|
1742
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1743
|
+
return new Promise((resolve, reject) => {
|
|
1744
|
+
// 检查浏览器是否支持 Web Bluetooth
|
|
1745
|
+
if (!navigator.bluetooth) {
|
|
1746
|
+
reject(createError(ErrorCodes.UNSUPPORTED_PLATFORM, '当前浏览器不支持 Web Bluetooth API,请使用 Chrome、Edge 或 Opera'));
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
this.initialized = true;
|
|
1750
|
+
resolve();
|
|
1751
|
+
});
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
startScanInternal() {
|
|
1755
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1756
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
1757
|
+
try {
|
|
1758
|
+
// Web Bluetooth 使用 requestDevice 而不是扫描
|
|
1759
|
+
// 这会弹出浏览器的选择设备对话框
|
|
1760
|
+
const options = {
|
|
1761
|
+
acceptAllDevices: true,
|
|
1762
|
+
};
|
|
1763
|
+
// 添加服务过滤
|
|
1764
|
+
if (this.options.services && this.options.services.length > 0) {
|
|
1765
|
+
options.filters = this.options.services.map(uuid => ({
|
|
1766
|
+
services: [uuid],
|
|
1767
|
+
}));
|
|
1768
|
+
}
|
|
1769
|
+
else {
|
|
1770
|
+
options.acceptAllDevices = true;
|
|
1771
|
+
}
|
|
1772
|
+
// 请求设备(浏览器会弹出选择框)
|
|
1773
|
+
this.device = yield navigator.bluetooth.requestDevice(options);
|
|
1774
|
+
// 监听设备广告(如果支持)
|
|
1775
|
+
if (this.device.watchAdvertisements) {
|
|
1776
|
+
this.device.addEventListener('advertisementreceived', (event) => {
|
|
1777
|
+
this.handleDeviceFound({
|
|
1778
|
+
deviceId: this.device.id,
|
|
1779
|
+
name: this.device.name,
|
|
1780
|
+
RSSI: event.rssi || -50,
|
|
1781
|
+
advertisData: event.manufacturerData,
|
|
1782
|
+
});
|
|
1783
|
+
});
|
|
1784
|
+
yield this.device.watchAdvertisements();
|
|
1785
|
+
}
|
|
1786
|
+
else {
|
|
1787
|
+
// 如果不支持广告监听,直接返回设备信息
|
|
1788
|
+
this.handleDeviceFound({
|
|
1789
|
+
deviceId: this.device.id,
|
|
1790
|
+
name: this.device.name,
|
|
1791
|
+
RSSI: -50, // 默认值
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
resolve();
|
|
1795
|
+
}
|
|
1796
|
+
catch (error) {
|
|
1797
|
+
if (error.name === 'NotFoundError') {
|
|
1798
|
+
reject(Errors.scanFailed('用户取消了设备选择'));
|
|
1799
|
+
}
|
|
1800
|
+
else {
|
|
1801
|
+
reject(handlePlatformError(error, 'web'));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
}));
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
stopScanInternal() {
|
|
1808
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1809
|
+
// Web Bluetooth 没有明确的停止扫描方法
|
|
1810
|
+
// 设备选择后扫描就结束了
|
|
1811
|
+
if (this.device && this.device.unwatchAdvertisements) {
|
|
1812
|
+
yield this.device.unwatchAdvertisements();
|
|
1813
|
+
}
|
|
1814
|
+
return Promise.resolve();
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
checkPermissions() {
|
|
1818
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1819
|
+
// Web Bluetooth 权限由浏览器自动管理
|
|
1820
|
+
// 通过用户手势触发 requestDevice 时会自动请求权限
|
|
1821
|
+
return true;
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
requestPermissions() {
|
|
1825
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1826
|
+
// Web Bluetooth 不需要显式请求权限
|
|
1827
|
+
return true;
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
onAdapterStateChange(callback) {
|
|
1831
|
+
this.adapterStateListeners.push(callback);
|
|
1832
|
+
// Web Bluetooth 没有适配器状态变化事件
|
|
1833
|
+
// 直接返回当前状态
|
|
1834
|
+
callback({
|
|
1835
|
+
available: !!navigator.bluetooth,
|
|
1836
|
+
discovering: this.state === 'scanning',
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
destroy() {
|
|
1840
|
+
super.destroy();
|
|
1841
|
+
this.device = null;
|
|
1842
|
+
this.server = null;
|
|
1843
|
+
}
|
|
1844
|
+
/**
|
|
1845
|
+
* 连接到设备(Web Bluetooth 特有)
|
|
1846
|
+
*/
|
|
1847
|
+
connect() {
|
|
1848
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1849
|
+
var _a;
|
|
1850
|
+
if (!this.device) {
|
|
1851
|
+
throw Errors.notInitialized();
|
|
1852
|
+
}
|
|
1853
|
+
try {
|
|
1854
|
+
this.server = (yield ((_a = this.device.gatt) === null || _a === void 0 ? void 0 : _a.connect())) || null;
|
|
1855
|
+
return this.server;
|
|
1856
|
+
}
|
|
1857
|
+
catch (error) {
|
|
1858
|
+
throw handlePlatformError(error, 'web');
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* 断开连接(Web Bluetooth 特有)
|
|
1864
|
+
*/
|
|
1865
|
+
disconnect() {
|
|
1866
|
+
var _a;
|
|
1867
|
+
if (this.device && ((_a = this.device.gatt) === null || _a === void 0 ? void 0 : _a.connected)) {
|
|
1868
|
+
this.device.gatt.disconnect();
|
|
1869
|
+
}
|
|
1870
|
+
this.server = null;
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* 获取已连接的服务(Web Bluetooth 特有)
|
|
1874
|
+
*/
|
|
1875
|
+
getServices() {
|
|
1876
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1877
|
+
if (!this.server) {
|
|
1878
|
+
throw Errors.notInitialized();
|
|
1879
|
+
}
|
|
1880
|
+
try {
|
|
1881
|
+
return yield this.server.getPrimaryServices();
|
|
1882
|
+
}
|
|
1883
|
+
catch (error) {
|
|
1884
|
+
throw handlePlatformError(error, 'web');
|
|
1885
|
+
}
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1890
|
+
* 检查浏览器是否支持 Web Bluetooth
|
|
1891
|
+
*/
|
|
1892
|
+
function isWebBluetoothSupported() {
|
|
1893
|
+
return 'bluetooth' in navigator && typeof navigator.bluetooth.requestDevice === 'function';
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1728
1896
|
/**
|
|
1729
1897
|
* 创建蓝牙扫描器
|
|
1730
1898
|
* @param options 创建选项
|
|
@@ -1734,6 +1902,14 @@ function createScanner(options = {}) {
|
|
|
1734
1902
|
const { type = 'auto', platformConfig = {} } = options;
|
|
1735
1903
|
const platform = getPlatform();
|
|
1736
1904
|
const app = isApp();
|
|
1905
|
+
// 检测是否在浏览器环境
|
|
1906
|
+
const isWeb = typeof window !== 'undefined' && !app;
|
|
1907
|
+
// 如果是 Web 环境或指定使用 Web 扫描器
|
|
1908
|
+
if (type === 'web' || (type === 'auto' && isWeb)) {
|
|
1909
|
+
const webScanner = new WebScanner();
|
|
1910
|
+
Object.assign(webScanner, { platformConfig });
|
|
1911
|
+
return webScanner;
|
|
1912
|
+
}
|
|
1737
1913
|
// 根据类型和平台选择合适的扫描器
|
|
1738
1914
|
if (type === 'uniapp' || (type === 'auto' && !app)) {
|
|
1739
1915
|
// 使用 UniApp 标准 API
|
|
@@ -1799,6 +1975,7 @@ exports.Errors = Errors;
|
|
|
1799
1975
|
exports.HarmonyNativeScanner = HarmonyNativeScanner;
|
|
1800
1976
|
exports.IOSNativeScanner = IOSNativeScanner;
|
|
1801
1977
|
exports.UniAppScanner = UniAppScanner;
|
|
1978
|
+
exports.WebScanner = WebScanner;
|
|
1802
1979
|
exports.arrayBufferToBase64 = arrayBufferToBase64;
|
|
1803
1980
|
exports.base64ToArrayBuffer = base64ToArrayBuffer;
|
|
1804
1981
|
exports.checkPermissions = checkPermissions;
|
|
@@ -1813,6 +1990,7 @@ exports.getPlatformName = getPlatformName;
|
|
|
1813
1990
|
exports.isApp = isApp;
|
|
1814
1991
|
exports.isBluetoothSupported = isBluetoothSupported;
|
|
1815
1992
|
exports.isPlatform = isPlatform;
|
|
1993
|
+
exports.isWebBluetoothSupported = isWebBluetoothSupported;
|
|
1816
1994
|
exports.matchUUID = matchUUID;
|
|
1817
1995
|
exports.parseAdvertisementData = parseAdvertisementData;
|
|
1818
1996
|
exports.requestPermissions = requestPermissions;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseScanner } from '../core/base-scanner';
|
|
2
|
+
import { Platform, AdapterState } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Web 浏览器蓝牙扫描器
|
|
5
|
+
* 使用 Web Bluetooth API
|
|
6
|
+
*/
|
|
7
|
+
export declare class WebScanner extends BaseScanner {
|
|
8
|
+
private device;
|
|
9
|
+
private server;
|
|
10
|
+
getPlatform(): Platform;
|
|
11
|
+
init(): Promise<void>;
|
|
12
|
+
protected startScanInternal(): Promise<void>;
|
|
13
|
+
protected stopScanInternal(): Promise<void>;
|
|
14
|
+
checkPermissions(): Promise<boolean>;
|
|
15
|
+
requestPermissions(): Promise<boolean>;
|
|
16
|
+
onAdapterStateChange(callback: (state: AdapterState) => void): void;
|
|
17
|
+
destroy(): void;
|
|
18
|
+
/**
|
|
19
|
+
* 连接到设备(Web Bluetooth 特有)
|
|
20
|
+
*/
|
|
21
|
+
connect(): Promise<BluetoothRemoteGATTServer | null>;
|
|
22
|
+
/**
|
|
23
|
+
* 断开连接(Web Bluetooth 特有)
|
|
24
|
+
*/
|
|
25
|
+
disconnect(): void;
|
|
26
|
+
/**
|
|
27
|
+
* 获取已连接的服务(Web Bluetooth 特有)
|
|
28
|
+
*/
|
|
29
|
+
getServices(): Promise<BluetoothRemoteGATTService[]>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 检查浏览器是否支持 Web Bluetooth
|
|
33
|
+
*/
|
|
34
|
+
export declare function isWebBluetoothSupported(): boolean;
|
|
35
|
+
//# sourceMappingURL=web-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-scanner.d.ts","sourceRoot":"","sources":["../../src/platforms/web-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EACL,QAAQ,EACR,YAAY,EAIb,MAAM,UAAU,CAAC;AAIlB;;;GAGG;AACH,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,MAAM,CAA0C;IAExD,WAAW,IAAI,QAAQ;IAIjB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;cAgBX,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;cAqDlC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3C,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAMpC,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAK5C,oBAAoB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAWnE,OAAO,IAAI,IAAI;IAMf;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IAa1D;;OAEG;IACH,UAAU,IAAI,IAAI;IAOlB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAW3D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD"}
|
package/package.json
CHANGED
package/src/factory.ts
CHANGED
|
@@ -3,12 +3,13 @@ import { UniAppScanner } from './platforms/uniapp-scanner';
|
|
|
3
3
|
import { AndroidNativeScanner } from './platforms/android-native';
|
|
4
4
|
import { IOSNativeScanner } from './platforms/ios-native';
|
|
5
5
|
import { HarmonyNativeScanner } from './platforms/harmony-native';
|
|
6
|
+
import { WebScanner } from './platforms/web-scanner';
|
|
6
7
|
import { getPlatform, isApp } from './utils/platform';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* 扫描器类型
|
|
10
11
|
*/
|
|
11
|
-
export type ScannerType = 'auto' | 'uniapp' | 'native';
|
|
12
|
+
export type ScannerType = 'auto' | 'uniapp' | 'native' | 'web';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* 创建扫描器的选项
|
|
@@ -30,6 +31,16 @@ export function createScanner(options: CreateScannerOptions = {}): IBLEScanner {
|
|
|
30
31
|
const platform = getPlatform();
|
|
31
32
|
const app = isApp();
|
|
32
33
|
|
|
34
|
+
// 检测是否在浏览器环境
|
|
35
|
+
const isWeb = typeof window !== 'undefined' && !app;
|
|
36
|
+
|
|
37
|
+
// 如果是 Web 环境或指定使用 Web 扫描器
|
|
38
|
+
if (type === 'web' || (type === 'auto' && isWeb)) {
|
|
39
|
+
const webScanner = new WebScanner();
|
|
40
|
+
Object.assign(webScanner, { platformConfig });
|
|
41
|
+
return webScanner;
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
// 根据类型和平台选择合适的扫描器
|
|
34
45
|
if (type === 'uniapp' || (type === 'auto' && !app)) {
|
|
35
46
|
// 使用 UniApp 标准 API
|
|
@@ -45,17 +56,17 @@ export function createScanner(options: CreateScannerOptions = {}): IBLEScanner {
|
|
|
45
56
|
const androidScanner = new AndroidNativeScanner();
|
|
46
57
|
Object.assign(androidScanner, { platformConfig });
|
|
47
58
|
return androidScanner;
|
|
48
|
-
|
|
59
|
+
|
|
49
60
|
case Platform.IOS:
|
|
50
61
|
const iosScanner = new IOSNativeScanner();
|
|
51
62
|
Object.assign(iosScanner, { platformConfig });
|
|
52
63
|
return iosScanner;
|
|
53
|
-
|
|
64
|
+
|
|
54
65
|
case Platform.HARMONY:
|
|
55
66
|
const harmonyScanner = new HarmonyNativeScanner();
|
|
56
67
|
Object.assign(harmonyScanner, { platformConfig });
|
|
57
68
|
return harmonyScanner;
|
|
58
|
-
|
|
69
|
+
|
|
59
70
|
default:
|
|
60
71
|
// 未知平台使用 UniApp API
|
|
61
72
|
const defaultScanner = new UniAppScanner();
|
|
@@ -70,6 +81,14 @@ export function createScanner(options: CreateScannerOptions = {}): IBLEScanner {
|
|
|
70
81
|
return defaultScanner;
|
|
71
82
|
}
|
|
72
83
|
|
|
84
|
+
/**
|
|
85
|
+
* 创建 Web 扫描器
|
|
86
|
+
* 使用 Web Bluetooth API,适用于浏览器环境
|
|
87
|
+
*/
|
|
88
|
+
export function createWebScanner(platformConfig?: PlatformConfig): IBLEScanner {
|
|
89
|
+
return createScanner({ type: 'web', platformConfig });
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
/**
|
|
74
93
|
* 创建 UniApp 扫描器
|
|
75
94
|
* 使用 UniApp 标准蓝牙 API,兼容所有平台
|
package/src/index.ts
CHANGED
|
@@ -48,6 +48,7 @@ export { UniAppScanner } from './platforms/uniapp-scanner';
|
|
|
48
48
|
export { AndroidNativeScanner } from './platforms/android-native';
|
|
49
49
|
export { IOSNativeScanner } from './platforms/ios-native';
|
|
50
50
|
export { HarmonyNativeScanner } from './platforms/harmony-native';
|
|
51
|
+
export { WebScanner, isWebBluetoothSupported } from './platforms/web-scanner';
|
|
51
52
|
|
|
52
53
|
// 默认导出
|
|
53
54
|
import { createScanner } from './factory';
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { BaseScanner } from '../core/base-scanner';
|
|
2
|
+
import {
|
|
3
|
+
Platform,
|
|
4
|
+
AdapterState,
|
|
5
|
+
BLEError,
|
|
6
|
+
PlatformConfig,
|
|
7
|
+
BLEDevice,
|
|
8
|
+
} from '../types';
|
|
9
|
+
import { Errors, createError, ErrorCodes, handlePlatformError } from '../utils/errors';
|
|
10
|
+
import { normalizeDeviceData } from '../utils/data-parser';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Web 浏览器蓝牙扫描器
|
|
14
|
+
* 使用 Web Bluetooth API
|
|
15
|
+
*/
|
|
16
|
+
export class WebScanner extends BaseScanner {
|
|
17
|
+
private device: BluetoothDevice | null = null;
|
|
18
|
+
private server: BluetoothRemoteGATTServer | null = null;
|
|
19
|
+
|
|
20
|
+
getPlatform(): Platform {
|
|
21
|
+
return Platform.UNKNOWN;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async init(): Promise<void> {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
// 检查浏览器是否支持 Web Bluetooth
|
|
27
|
+
if (!navigator.bluetooth) {
|
|
28
|
+
reject(createError(
|
|
29
|
+
ErrorCodes.UNSUPPORTED_PLATFORM,
|
|
30
|
+
'当前浏览器不支持 Web Bluetooth API,请使用 Chrome、Edge 或 Opera'
|
|
31
|
+
));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.initialized = true;
|
|
36
|
+
resolve();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected async startScanInternal(): Promise<void> {
|
|
41
|
+
return new Promise(async (resolve, reject) => {
|
|
42
|
+
try {
|
|
43
|
+
// Web Bluetooth 使用 requestDevice 而不是扫描
|
|
44
|
+
// 这会弹出浏览器的选择设备对话框
|
|
45
|
+
const options: RequestDeviceOptions = {
|
|
46
|
+
acceptAllDevices: true,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// 添加服务过滤
|
|
50
|
+
if (this.options.services && this.options.services.length > 0) {
|
|
51
|
+
options.filters = this.options.services.map(uuid => ({
|
|
52
|
+
services: [uuid],
|
|
53
|
+
}));
|
|
54
|
+
} else {
|
|
55
|
+
options.acceptAllDevices = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 请求设备(浏览器会弹出选择框)
|
|
59
|
+
this.device = await navigator.bluetooth.requestDevice(options);
|
|
60
|
+
|
|
61
|
+
// 监听设备广告(如果支持)
|
|
62
|
+
if (this.device.watchAdvertisements) {
|
|
63
|
+
this.device.addEventListener('advertisementreceived', (event: any) => {
|
|
64
|
+
this.handleDeviceFound({
|
|
65
|
+
deviceId: this.device!.id,
|
|
66
|
+
name: this.device!.name,
|
|
67
|
+
RSSI: event.rssi || -50,
|
|
68
|
+
advertisData: event.manufacturerData,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await this.device.watchAdvertisements();
|
|
73
|
+
} else {
|
|
74
|
+
// 如果不支持广告监听,直接返回设备信息
|
|
75
|
+
this.handleDeviceFound({
|
|
76
|
+
deviceId: this.device.id,
|
|
77
|
+
name: this.device.name,
|
|
78
|
+
RSSI: -50, // 默认值
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
resolve();
|
|
83
|
+
} catch (error: any) {
|
|
84
|
+
if (error.name === 'NotFoundError') {
|
|
85
|
+
reject(Errors.scanFailed('用户取消了设备选择'));
|
|
86
|
+
} else {
|
|
87
|
+
reject(handlePlatformError(error, 'web'));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
protected async stopScanInternal(): Promise<void> {
|
|
94
|
+
// Web Bluetooth 没有明确的停止扫描方法
|
|
95
|
+
// 设备选择后扫描就结束了
|
|
96
|
+
if (this.device && this.device.unwatchAdvertisements) {
|
|
97
|
+
await this.device.unwatchAdvertisements();
|
|
98
|
+
}
|
|
99
|
+
return Promise.resolve();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async checkPermissions(): Promise<boolean> {
|
|
103
|
+
// Web Bluetooth 权限由浏览器自动管理
|
|
104
|
+
// 通过用户手势触发 requestDevice 时会自动请求权限
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async requestPermissions(): Promise<boolean> {
|
|
109
|
+
// Web Bluetooth 不需要显式请求权限
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
onAdapterStateChange(callback: (state: AdapterState) => void): void {
|
|
114
|
+
this.adapterStateListeners.push(callback);
|
|
115
|
+
|
|
116
|
+
// Web Bluetooth 没有适配器状态变化事件
|
|
117
|
+
// 直接返回当前状态
|
|
118
|
+
callback({
|
|
119
|
+
available: !!navigator.bluetooth,
|
|
120
|
+
discovering: this.state === 'scanning',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
destroy(): void {
|
|
125
|
+
super.destroy();
|
|
126
|
+
this.device = null;
|
|
127
|
+
this.server = null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 连接到设备(Web Bluetooth 特有)
|
|
132
|
+
*/
|
|
133
|
+
async connect(): Promise<BluetoothRemoteGATTServer | null> {
|
|
134
|
+
if (!this.device) {
|
|
135
|
+
throw Errors.notInitialized();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
this.server = await this.device.gatt?.connect() || null;
|
|
140
|
+
return this.server;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
throw handlePlatformError(error, 'web');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 断开连接(Web Bluetooth 特有)
|
|
148
|
+
*/
|
|
149
|
+
disconnect(): void {
|
|
150
|
+
if (this.device && this.device.gatt?.connected) {
|
|
151
|
+
this.device.gatt.disconnect();
|
|
152
|
+
}
|
|
153
|
+
this.server = null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 获取已连接的服务(Web Bluetooth 特有)
|
|
158
|
+
*/
|
|
159
|
+
async getServices(): Promise<BluetoothRemoteGATTService[]> {
|
|
160
|
+
if (!this.server) {
|
|
161
|
+
throw Errors.notInitialized();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
return await this.server.getPrimaryServices();
|
|
166
|
+
} catch (error) {
|
|
167
|
+
throw handlePlatformError(error, 'web');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 检查浏览器是否支持 Web Bluetooth
|
|
174
|
+
*/
|
|
175
|
+
export function isWebBluetoothSupported(): boolean {
|
|
176
|
+
return 'bluetooth' in navigator && typeof navigator.bluetooth.requestDevice === 'function';
|
|
177
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Bluetooth API 类型声明
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
interface BluetoothDevice extends EventTarget {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly name: string | null;
|
|
8
|
+
readonly gatt: BluetoothRemoteGATTServer | null;
|
|
9
|
+
readonly uuids: string[];
|
|
10
|
+
|
|
11
|
+
watchAdvertisements(): Promise<void>;
|
|
12
|
+
unwatchAdvertisements(): Promise<void>;
|
|
13
|
+
|
|
14
|
+
addEventListener(type: 'advertisementreceived', listener: (event: BluetoothAdvertisingEvent) => void): void;
|
|
15
|
+
addEventListener(type: string, listener: EventListenerOrEventListenerObject): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface BluetoothRemoteGATTServer {
|
|
19
|
+
readonly device: BluetoothDevice;
|
|
20
|
+
readonly connected: boolean;
|
|
21
|
+
|
|
22
|
+
connect(): Promise<BluetoothRemoteGATTServer>;
|
|
23
|
+
disconnect(): void;
|
|
24
|
+
getPrimaryService(service: string | number): Promise<BluetoothRemoteGATTService>;
|
|
25
|
+
getPrimaryServices(service?: string | number): Promise<BluetoothRemoteGATTService[]>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface BluetoothRemoteGATTService extends EventTarget {
|
|
29
|
+
readonly device: BluetoothDevice;
|
|
30
|
+
readonly uuid: string;
|
|
31
|
+
readonly isPrimary: boolean;
|
|
32
|
+
|
|
33
|
+
getCharacteristic(characteristic: string | number): Promise<BluetoothRemoteGATTCharacteristic>;
|
|
34
|
+
getCharacteristics(characteristic?: string | number): Promise<BluetoothRemoteGATTCharacteristic[]>;
|
|
35
|
+
getIncludedService(service: string | number): Promise<BluetoothRemoteGATTService>;
|
|
36
|
+
getIncludedServices(service?: string | number): Promise<BluetoothRemoteGATTService[]>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface BluetoothRemoteGATTCharacteristic extends EventTarget {
|
|
40
|
+
readonly service: BluetoothRemoteGATTService;
|
|
41
|
+
readonly uuid: string;
|
|
42
|
+
readonly properties: BluetoothCharacteristicProperties;
|
|
43
|
+
readonly value: DataView | null;
|
|
44
|
+
|
|
45
|
+
readValue(): Promise<DataView>;
|
|
46
|
+
writeValue(value: BufferSource): Promise<void>;
|
|
47
|
+
startNotifications(): Promise<BluetoothRemoteGATTCharacteristic>;
|
|
48
|
+
stopNotifications(): Promise<BluetoothRemoteGATTCharacteristic>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface BluetoothCharacteristicProperties {
|
|
52
|
+
readonly broadcast: boolean;
|
|
53
|
+
readonly read: boolean;
|
|
54
|
+
readonly writeWithoutResponse: boolean;
|
|
55
|
+
readonly write: boolean;
|
|
56
|
+
readonly notify: boolean;
|
|
57
|
+
readonly indicate: boolean;
|
|
58
|
+
readonly authenticatedSignedWrites: boolean;
|
|
59
|
+
readonly reliableWrite: boolean;
|
|
60
|
+
readonly writableAuxiliaries: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface BluetoothAdvertisingEvent extends Event {
|
|
64
|
+
readonly device: BluetoothDevice;
|
|
65
|
+
readonly rssi: number;
|
|
66
|
+
readonly txPower: number;
|
|
67
|
+
readonly manufacturerData: Map<number, DataView>;
|
|
68
|
+
readonly serviceData: Map<string, DataView>;
|
|
69
|
+
readonly uuids: string[];
|
|
70
|
+
readonly name: string | null;
|
|
71
|
+
readonly appearance: number | null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface BluetoothScanFilter {
|
|
75
|
+
services?: string[];
|
|
76
|
+
name?: string;
|
|
77
|
+
namePrefix?: string;
|
|
78
|
+
manufacturerData?: Map<number, BluetoothManufacturerDataFilter>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface BluetoothManufacturerDataFilter {
|
|
82
|
+
companyIdentifier: number;
|
|
83
|
+
dataPrefix?: DataView;
|
|
84
|
+
mask?: DataView;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface RequestDeviceOptions {
|
|
88
|
+
filters?: BluetoothScanFilter[];
|
|
89
|
+
optionalServices?: string[];
|
|
90
|
+
acceptAllDevices?: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface Bluetooth extends EventTarget {
|
|
94
|
+
requestDevice(options: RequestDeviceOptions): Promise<BluetoothDevice>;
|
|
95
|
+
getAvailability(): Promise<boolean>;
|
|
96
|
+
|
|
97
|
+
addEventListener(type: 'availabilitychanged', listener: (event: Event) => void): void;
|
|
98
|
+
addEventListener(type: string, listener: EventListenerOrEventListenerObject): void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface Navigator {
|
|
102
|
+
bluetooth: Bluetooth;
|
|
103
|
+
}
|