@fww_123/uni-ble-scanner 1.0.0

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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/dist/core/base-scanner.d.ts +99 -0
  4. package/dist/core/base-scanner.d.ts.map +1 -0
  5. package/dist/factory.d.ts +44 -0
  6. package/dist/factory.d.ts.map +1 -0
  7. package/dist/index.d.ts +15 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.esm.js +1791 -0
  10. package/dist/index.js +1818 -0
  11. package/dist/platforms/android-native.d.ts +30 -0
  12. package/dist/platforms/android-native.d.ts.map +1 -0
  13. package/dist/platforms/harmony-native.d.ts +24 -0
  14. package/dist/platforms/harmony-native.d.ts.map +1 -0
  15. package/dist/platforms/ios-native.d.ts +27 -0
  16. package/dist/platforms/ios-native.d.ts.map +1 -0
  17. package/dist/platforms/uniapp-scanner.d.ts +30 -0
  18. package/dist/platforms/uniapp-scanner.d.ts.map +1 -0
  19. package/dist/types.d.ts +170 -0
  20. package/dist/types.d.ts.map +1 -0
  21. package/dist/utils/data-parser.d.ts +32 -0
  22. package/dist/utils/data-parser.d.ts.map +1 -0
  23. package/dist/utils/errors.d.ts +27 -0
  24. package/dist/utils/errors.d.ts.map +1 -0
  25. package/dist/utils/permissions.d.ts +9 -0
  26. package/dist/utils/permissions.d.ts.map +1 -0
  27. package/dist/utils/platform.d.ts +18 -0
  28. package/dist/utils/platform.d.ts.map +1 -0
  29. package/package.json +58 -0
  30. package/src/core/base-scanner.ts +309 -0
  31. package/src/factory.ts +116 -0
  32. package/src/index.ts +54 -0
  33. package/src/platforms/android-native.ts +300 -0
  34. package/src/platforms/harmony-native.ts +267 -0
  35. package/src/platforms/ios-native.ts +264 -0
  36. package/src/platforms/uniapp-scanner.ts +171 -0
  37. package/src/types/global.d.ts +25 -0
  38. package/src/types/uni-types.d.ts +83 -0
  39. package/src/types.ts +178 -0
  40. package/src/utils/data-parser.ts +217 -0
  41. package/src/utils/errors.ts +105 -0
  42. package/src/utils/permissions.ts +244 -0
  43. package/src/utils/platform.ts +70 -0
package/dist/index.js ADDED
@@ -0,0 +1,1818 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * 扫描状态
7
+ */
8
+ exports.ScanState = void 0;
9
+ (function (ScanState) {
10
+ ScanState["IDLE"] = "idle";
11
+ ScanState["SCANNING"] = "scanning";
12
+ ScanState["STOPPING"] = "stopping";
13
+ ScanState["ERROR"] = "error";
14
+ })(exports.ScanState || (exports.ScanState = {}));
15
+ /**
16
+ * 平台类型
17
+ */
18
+ exports.Platform = void 0;
19
+ (function (Platform) {
20
+ Platform["ANDROID"] = "android";
21
+ Platform["IOS"] = "ios";
22
+ Platform["HARMONY"] = "harmony";
23
+ Platform["UNKNOWN"] = "unknown";
24
+ })(exports.Platform || (exports.Platform = {}));
25
+
26
+ /******************************************************************************
27
+ Copyright (c) Microsoft Corporation.
28
+
29
+ Permission to use, copy, modify, and/or distribute this software for any
30
+ purpose with or without fee is hereby granted.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
33
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
34
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
35
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
36
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
37
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
38
+ PERFORMANCE OF THIS SOFTWARE.
39
+ ***************************************************************************** */
40
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
41
+
42
+
43
+ function __awaiter(thisArg, _arguments, P, generator) {
44
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
45
+ return new (P || (P = Promise))(function (resolve, reject) {
46
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
47
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
48
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
49
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
50
+ });
51
+ }
52
+
53
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
54
+ var e = new Error(message);
55
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
56
+ };
57
+
58
+ /**
59
+ * 错误码定义
60
+ */
61
+ const ErrorCodes = {
62
+ // 通用错误
63
+ UNKNOWN_ERROR: 1000,
64
+ NOT_INITIALIZED: 1001,
65
+ ALREADY_SCANNING: 1002,
66
+ NOT_SCANNING: 1003,
67
+ PERMISSION_DENIED: 1004,
68
+ BLUETOOTH_DISABLED: 1005,
69
+ UNSUPPORTED_PLATFORM: 1006,
70
+ // 蓝牙特定错误
71
+ ADAPTER_NOT_AVAILABLE: 2001,
72
+ SCAN_FAILED: 2002,
73
+ DEVICE_NOT_FOUND: 2003,
74
+ CONNECTION_FAILED: 2004,
75
+ // 平台特定错误
76
+ ANDROID_ERROR: 3000,
77
+ IOS_ERROR: 4000,
78
+ HARMONY_ERROR: 5000,
79
+ };
80
+ /**
81
+ * 创建错误对象
82
+ */
83
+ function createError(code, message, platformCode, originalError) {
84
+ return {
85
+ code,
86
+ message,
87
+ platformCode,
88
+ originalError
89
+ };
90
+ }
91
+ /**
92
+ * 通用错误
93
+ */
94
+ const Errors = {
95
+ notInitialized: () => createError(ErrorCodes.NOT_INITIALIZED, '蓝牙适配器未初始化,请先调用 init()'),
96
+ alreadyScanning: () => createError(ErrorCodes.ALREADY_SCANNING, '扫描已在进行中'),
97
+ notScanning: () => createError(ErrorCodes.NOT_SCANNING, '扫描未在进行中'),
98
+ permissionDenied: () => createError(ErrorCodes.PERMISSION_DENIED, '蓝牙权限被拒绝'),
99
+ bluetoothDisabled: () => createError(ErrorCodes.BLUETOOTH_DISABLED, '蓝牙未开启'),
100
+ unsupportedPlatform: () => createError(ErrorCodes.UNSUPPORTED_PLATFORM, '当前平台不支持蓝牙功能'),
101
+ adapterNotAvailable: () => createError(ErrorCodes.ADAPTER_NOT_AVAILABLE, '蓝牙适配器不可用'),
102
+ scanFailed: (reason) => createError(ErrorCodes.SCAN_FAILED, `扫描失败: ${reason || '未知原因'}`),
103
+ };
104
+ /**
105
+ * 处理平台特定错误
106
+ */
107
+ function handlePlatformError(error, platform) {
108
+ const platformCode = (error === null || error === void 0 ? void 0 : error.code) || (error === null || error === void 0 ? void 0 : error.errCode);
109
+ const message = (error === null || error === void 0 ? void 0 : error.message) || (error === null || error === void 0 ? void 0 : error.errMsg) || '未知错误';
110
+ let code = ErrorCodes.UNKNOWN_ERROR;
111
+ switch (platform) {
112
+ case 'android':
113
+ code = ErrorCodes.ANDROID_ERROR;
114
+ break;
115
+ case 'ios':
116
+ code = ErrorCodes.IOS_ERROR;
117
+ break;
118
+ case 'harmony':
119
+ code = ErrorCodes.HARMONY_ERROR;
120
+ break;
121
+ }
122
+ return createError(code, `${platform}平台错误: ${message}`, platformCode, error);
123
+ }
124
+
125
+ /**
126
+ * 解析广播数据
127
+ */
128
+ function parseAdvertisementData(data) {
129
+ const result = {};
130
+ if (!data) {
131
+ return result;
132
+ }
133
+ let buffer;
134
+ if (typeof data === 'string') {
135
+ // Base64 解码
136
+ buffer = base64ToArrayBuffer(data);
137
+ }
138
+ else {
139
+ buffer = data;
140
+ }
141
+ const view = new DataView(buffer);
142
+ let offset = 0;
143
+ const manufacturerData = {};
144
+ const serviceUuids = [];
145
+ while (offset < view.byteLength) {
146
+ const length = view.getUint8(offset);
147
+ if (length === 0)
148
+ break;
149
+ const type = view.getUint8(offset + 1);
150
+ const dataOffset = offset + 2;
151
+ const dataLength = length - 1;
152
+ switch (type) {
153
+ case 0x01: // Flags
154
+ const flags = view.getUint8(dataOffset);
155
+ result.isConnectable = (flags & 0x02) !== 0;
156
+ break;
157
+ case 0x02: // 16-bit Service UUIDs (partial)
158
+ case 0x03: // 16-bit Service UUIDs (complete)
159
+ for (let i = 0; i < dataLength; i += 2) {
160
+ const uuid = view.getUint16(dataOffset + i, true).toString(16).padStart(4, '0');
161
+ serviceUuids.push(`0000${uuid}-0000-1000-8000-00805f9b34fb`);
162
+ }
163
+ break;
164
+ case 0x04: // 32-bit Service UUIDs (partial)
165
+ case 0x05: // 32-bit Service UUIDs (complete)
166
+ for (let i = 0; i < dataLength; i += 4) {
167
+ const uuid = view.getUint32(dataOffset + i, true).toString(16).padStart(8, '0');
168
+ serviceUuids.push(`${uuid}-0000-1000-8000-00805f9b34fb`);
169
+ }
170
+ break;
171
+ case 0x06: // 128-bit Service UUIDs (partial)
172
+ case 0x07: // 128-bit Service UUIDs (complete)
173
+ for (let i = 0; i < dataLength; i += 16) {
174
+ const uuid = parseUUID(buffer.slice(dataOffset + i, dataOffset + i + 16));
175
+ serviceUuids.push(uuid);
176
+ }
177
+ break;
178
+ case 0x08: // Shortened Local Name
179
+ case 0x09: // Complete Local Name
180
+ result.localName = decodeUTF8(buffer.slice(dataOffset, dataOffset + dataLength));
181
+ break;
182
+ case 0x0A: // TX Power Level
183
+ result.txPowerLevel = view.getInt8(dataOffset);
184
+ break;
185
+ case 0xFF: // Manufacturer Specific Data
186
+ const companyId = view.getUint16(dataOffset, true);
187
+ const companyIdHex = companyId.toString(16).padStart(4, '0');
188
+ manufacturerData[companyIdHex] = buffer.slice(dataOffset + 2, dataOffset + dataLength);
189
+ break;
190
+ }
191
+ offset += length + 1;
192
+ }
193
+ if (Object.keys(manufacturerData).length > 0) {
194
+ result.manufacturerData = manufacturerData;
195
+ }
196
+ if (serviceUuids.length > 0) {
197
+ result.serviceUuids = serviceUuids;
198
+ }
199
+ return result;
200
+ }
201
+ /**
202
+ * Base64 转 ArrayBuffer
203
+ */
204
+ function base64ToArrayBuffer(base64) {
205
+ const binary = atob(base64);
206
+ const buffer = new ArrayBuffer(binary.length);
207
+ const view = new Uint8Array(buffer);
208
+ for (let i = 0; i < binary.length; i++) {
209
+ view[i] = binary.charCodeAt(i);
210
+ }
211
+ return buffer;
212
+ }
213
+ /**
214
+ * ArrayBuffer 转 Base64
215
+ */
216
+ function arrayBufferToBase64(buffer) {
217
+ const bytes = new Uint8Array(buffer);
218
+ let binary = '';
219
+ for (let i = 0; i < bytes.byteLength; i++) {
220
+ binary += String.fromCharCode(bytes[i]);
221
+ }
222
+ return btoa(binary);
223
+ }
224
+ /**
225
+ * 解析 UUID
226
+ */
227
+ function parseUUID(buffer) {
228
+ const view = new DataView(buffer);
229
+ const parts = [
230
+ view.getUint32(0, false).toString(16).padStart(8, '0'),
231
+ view.getUint16(4, false).toString(16).padStart(4, '0'),
232
+ view.getUint16(6, false).toString(16).padStart(4, '0'),
233
+ view.getUint16(8, false).toString(16).padStart(4, '0'),
234
+ view.getUint32(10, false).toString(16).padStart(8, '0') +
235
+ view.getUint16(14, false).toString(16).padStart(4, '0'),
236
+ ];
237
+ return `${parts[0]}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`;
238
+ }
239
+ /**
240
+ * UTF-8 解码
241
+ */
242
+ function decodeUTF8(buffer) {
243
+ const decoder = new TextDecoder('utf-8');
244
+ return decoder.decode(buffer);
245
+ }
246
+ /**
247
+ * 标准化设备数据
248
+ */
249
+ function normalizeDeviceData(device) {
250
+ const normalized = {
251
+ deviceId: device.deviceId || '',
252
+ name: device.name || device.localName,
253
+ RSSI: device.RSSI || device.rssi || -100,
254
+ };
255
+ // 处理广播数据
256
+ if (device.advertisData) {
257
+ normalized.advertisData = device.advertisData;
258
+ if (typeof device.advertisData === 'string') {
259
+ normalized.advertisDataBase64 = device.advertisData;
260
+ }
261
+ else {
262
+ normalized.advertisDataBase64 = arrayBufferToBase64(device.advertisData);
263
+ }
264
+ // 解析广播数据
265
+ const parsed = parseAdvertisementData(device.advertisData);
266
+ Object.assign(normalized, parsed);
267
+ }
268
+ // 处理制造商数据
269
+ if (device.manufacturerData) {
270
+ normalized.manufacturerData = device.manufacturerData;
271
+ }
272
+ // 处理服务UUID
273
+ if (device.serviceUuids) {
274
+ normalized.serviceUuids = device.serviceUuids;
275
+ }
276
+ // 平台特定数据
277
+ normalized.platformData = {
278
+ raw: device,
279
+ };
280
+ return normalized;
281
+ }
282
+ /**
283
+ * 格式化 UUID (统一格式)
284
+ */
285
+ function formatUUID(uuid) {
286
+ // 移除所有非十六进制字符
287
+ const clean = uuid.toLowerCase().replace(/[^0-9a-f]/g, '');
288
+ if (clean.length === 4) {
289
+ // 16-bit UUID
290
+ return `0000${clean}-0000-1000-8000-00805f9b34fb`;
291
+ }
292
+ else if (clean.length === 8) {
293
+ // 32-bit UUID
294
+ return `${clean}-0000-1000-8000-00805f9b34fb`;
295
+ }
296
+ else if (clean.length === 32) {
297
+ // 128-bit UUID
298
+ return `${clean.slice(0, 8)}-${clean.slice(8, 12)}-${clean.slice(12, 16)}-${clean.slice(16, 20)}-${clean.slice(20)}`;
299
+ }
300
+ return uuid;
301
+ }
302
+ /**
303
+ * 检查 UUID 是否匹配
304
+ */
305
+ function matchUUID(uuid1, uuid2) {
306
+ return formatUUID(uuid1) === formatUUID(uuid2);
307
+ }
308
+
309
+ /**
310
+ * 扫描器基类
311
+ */
312
+ class BaseScanner {
313
+ constructor() {
314
+ this.state = exports.ScanState.IDLE;
315
+ this.discoveredDevices = new Map();
316
+ this.callbacks = {};
317
+ this.options = {};
318
+ this.platformConfig = {};
319
+ this.initialized = false;
320
+ this.timeoutId = null;
321
+ this.adapterStateListeners = [];
322
+ }
323
+ /**
324
+ * 开始扫描
325
+ */
326
+ startScan() {
327
+ return __awaiter(this, arguments, void 0, function* (options = {}, callbacks = {}) {
328
+ var _a, _b;
329
+ if (this.state === exports.ScanState.SCANNING) {
330
+ throw Errors.alreadyScanning();
331
+ }
332
+ if (!this.initialized) {
333
+ throw Errors.notInitialized();
334
+ }
335
+ // 检查权限
336
+ const hasPermission = yield this.checkPermissions();
337
+ if (!hasPermission) {
338
+ const granted = yield this.requestPermissions();
339
+ if (!granted) {
340
+ throw Errors.permissionDenied();
341
+ }
342
+ }
343
+ this.options = Object.assign(Object.assign({}, this.getDefaultOptions()), options);
344
+ this.callbacks = callbacks;
345
+ try {
346
+ this.setState(exports.ScanState.SCANNING);
347
+ // 清空之前的设备列表(如果不需要重复上报)
348
+ if (!this.options.allowDuplicates) {
349
+ this.clearDevices();
350
+ }
351
+ // 设置超时
352
+ if (this.options.timeout && this.options.timeout > 0) {
353
+ this.timeoutId = window.setTimeout(() => {
354
+ this.handleTimeout();
355
+ }, this.options.timeout);
356
+ }
357
+ yield this.startScanInternal();
358
+ (_b = (_a = this.callbacks).onScanStart) === null || _b === void 0 ? void 0 : _b.call(_a);
359
+ }
360
+ catch (error) {
361
+ this.setState(exports.ScanState.ERROR);
362
+ this.clearTimeout();
363
+ throw error;
364
+ }
365
+ });
366
+ }
367
+ /**
368
+ * 停止扫描
369
+ */
370
+ stopScan() {
371
+ return __awaiter(this, void 0, void 0, function* () {
372
+ var _a, _b;
373
+ if (this.state !== exports.ScanState.SCANNING) {
374
+ return;
375
+ }
376
+ this.setState(exports.ScanState.STOPPING);
377
+ this.clearTimeout();
378
+ try {
379
+ yield this.stopScanInternal();
380
+ this.setState(exports.ScanState.IDLE);
381
+ (_b = (_a = this.callbacks).onScanStop) === null || _b === void 0 ? void 0 : _b.call(_a);
382
+ }
383
+ catch (error) {
384
+ this.setState(exports.ScanState.ERROR);
385
+ throw error;
386
+ }
387
+ });
388
+ }
389
+ /**
390
+ * 获取已发现的设备列表
391
+ */
392
+ getDiscoveredDevices() {
393
+ return Array.from(this.discoveredDevices.values());
394
+ }
395
+ /**
396
+ * 清空设备列表
397
+ */
398
+ clearDevices() {
399
+ this.discoveredDevices.clear();
400
+ }
401
+ /**
402
+ * 获取当前扫描状态
403
+ */
404
+ getState() {
405
+ return this.state;
406
+ }
407
+ /**
408
+ * 销毁扫描器
409
+ */
410
+ destroy() {
411
+ this.stopScan();
412
+ this.clearDevices();
413
+ this.clearTimeout();
414
+ this.callbacks = {};
415
+ this.adapterStateListeners = [];
416
+ this.initialized = false;
417
+ }
418
+ /**
419
+ * 处理发现的设备
420
+ */
421
+ handleDeviceFound(rawDevice) {
422
+ var _a, _b;
423
+ try {
424
+ const device = normalizeDeviceData(rawDevice);
425
+ // 应用过滤器
426
+ if (!this.filterDevice(device)) {
427
+ return;
428
+ }
429
+ // 检查是否已存在
430
+ const existingDevice = this.discoveredDevices.get(device.deviceId);
431
+ if (existingDevice && !this.options.allowDuplicates) {
432
+ // 更新 RSSI
433
+ existingDevice.RSSI = device.RSSI;
434
+ return;
435
+ }
436
+ // 保存设备
437
+ this.discoveredDevices.set(device.deviceId, device);
438
+ // 触发回调
439
+ (_b = (_a = this.callbacks).onDeviceFound) === null || _b === void 0 ? void 0 : _b.call(_a, device);
440
+ }
441
+ catch (error) {
442
+ console.error('处理设备数据失败:', error);
443
+ }
444
+ }
445
+ /**
446
+ * 过滤设备
447
+ */
448
+ filterDevice(device) {
449
+ // 按名称过滤
450
+ if (this.options.nameFilter) {
451
+ const deviceName = device.name || '';
452
+ const filters = Array.isArray(this.options.nameFilter)
453
+ ? this.options.nameFilter
454
+ : [this.options.nameFilter];
455
+ const nameMatch = filters.some(filter => {
456
+ if (typeof filter === 'string') {
457
+ return deviceName.includes(filter);
458
+ }
459
+ return filter.test(deviceName);
460
+ });
461
+ if (!nameMatch)
462
+ return false;
463
+ }
464
+ // 按信号强度过滤
465
+ if (this.options.rssiThreshold !== undefined) {
466
+ if (device.RSSI < this.options.rssiThreshold) {
467
+ return false;
468
+ }
469
+ }
470
+ // 按服务UUID过滤
471
+ if (this.options.services && this.options.services.length > 0) {
472
+ if (!device.serviceUuids)
473
+ return false;
474
+ const hasMatchingService = this.options.services.some(service => device.serviceUuids.some(uuid => uuid.toLowerCase().includes(service.toLowerCase())));
475
+ if (!hasMatchingService)
476
+ return false;
477
+ }
478
+ // 按制造商数据过滤
479
+ if (this.options.manufacturerFilter !== undefined) {
480
+ if (!device.manufacturerData)
481
+ return false;
482
+ const filters = Array.isArray(this.options.manufacturerFilter)
483
+ ? this.options.manufacturerFilter
484
+ : [this.options.manufacturerFilter];
485
+ const manufacturerIds = Object.keys(device.manufacturerData).map(id => parseInt(id, 16));
486
+ const hasMatchingManufacturer = filters.some(filter => manufacturerIds.includes(filter));
487
+ if (!hasMatchingManufacturer)
488
+ return false;
489
+ }
490
+ return true;
491
+ }
492
+ /**
493
+ * 处理超时
494
+ */
495
+ handleTimeout() {
496
+ var _a, _b;
497
+ this.stopScan();
498
+ (_b = (_a = this.callbacks).onTimeout) === null || _b === void 0 ? void 0 : _b.call(_a);
499
+ }
500
+ /**
501
+ * 处理错误
502
+ */
503
+ handleError(error) {
504
+ var _a, _b;
505
+ const bleError = handlePlatformError(error, this.getPlatform());
506
+ this.setState(exports.ScanState.ERROR);
507
+ (_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, bleError);
508
+ }
509
+ /**
510
+ * 设置状态
511
+ */
512
+ setState(state) {
513
+ this.state = state;
514
+ }
515
+ /**
516
+ * 清除超时定时器
517
+ */
518
+ clearTimeout() {
519
+ if (this.timeoutId !== null) {
520
+ window.clearTimeout(this.timeoutId);
521
+ this.timeoutId = null;
522
+ }
523
+ }
524
+ /**
525
+ * 获取默认选项
526
+ */
527
+ getDefaultOptions() {
528
+ return {
529
+ timeout: 10000,
530
+ allowDuplicates: false,
531
+ };
532
+ }
533
+ /**
534
+ * 触发适配器状态变化
535
+ */
536
+ emitAdapterStateChange(state) {
537
+ this.adapterStateListeners.forEach(listener => listener(state));
538
+ }
539
+ }
540
+
541
+ /**
542
+ * 获取当前运行平台
543
+ */
544
+ function getPlatform() {
545
+ var _a;
546
+ // #ifdef APP-PLUS
547
+ const systemInfo = uni.getSystemInfoSync();
548
+ const platform = ((_a = systemInfo.platform) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
549
+ if (platform === 'android') {
550
+ return exports.Platform.ANDROID;
551
+ }
552
+ else if (platform === 'ios') {
553
+ return exports.Platform.IOS;
554
+ }
555
+ else if (platform === 'harmony' || platform === 'harmonyos') {
556
+ return exports.Platform.HARMONY;
557
+ }
558
+ // #endif
559
+ // #ifdef HARMONY
560
+ return exports.Platform.HARMONY;
561
+ }
562
+ /**
563
+ * 检查是否在指定平台运行
564
+ */
565
+ function isPlatform(platform) {
566
+ return getPlatform() === platform;
567
+ }
568
+ /**
569
+ * 检查是否是移动端APP环境
570
+ */
571
+ function isApp() {
572
+ // #ifdef APP-PLUS
573
+ return true;
574
+ }
575
+ /**
576
+ * 获取平台名称
577
+ */
578
+ function getPlatformName() {
579
+ const platform = getPlatform();
580
+ switch (platform) {
581
+ case exports.Platform.ANDROID:
582
+ return 'Android';
583
+ case exports.Platform.IOS:
584
+ return 'iOS';
585
+ case exports.Platform.HARMONY:
586
+ return 'HarmonyOS';
587
+ default:
588
+ return 'Unknown';
589
+ }
590
+ }
591
+
592
+ /**
593
+ * 安卓权限列表
594
+ */
595
+ const ANDROID_PERMISSIONS = {
596
+ // Android 12+ 需要的新权限
597
+ BLUETOOTH_SCAN: 'android.permission.BLUETOOTH_SCAN',
598
+ BLUETOOTH_CONNECT: 'android.permission.BLUETOOTH_CONNECT',
599
+ // Android 11 及以下需要的权限
600
+ BLUETOOTH: 'android.permission.BLUETOOTH',
601
+ BLUETOOTH_ADMIN: 'android.permission.BLUETOOTH_ADMIN',
602
+ // 位置权限(扫描需要)
603
+ ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION'};
604
+ /**
605
+ * iOS 不需要显式请求蓝牙权限,由系统自动处理
606
+ * 但需要在 Info.plist 中配置 NSBluetoothAlwaysUsageDescription
607
+ */
608
+ /**
609
+ * 鸿蒙权限列表
610
+ */
611
+ const HARMONY_PERMISSIONS = {
612
+ ACCESS_BLUETOOTH: 'ohos.permission.ACCESS_BLUETOOTH',
613
+ LOCATION: 'ohos.permission.LOCATION',
614
+ APPROXIMATELY_LOCATION: 'ohos.permission.APPROXIMATELY_LOCATION',
615
+ };
616
+ /**
617
+ * 检查权限
618
+ */
619
+ function checkPermissions() {
620
+ return __awaiter(this, void 0, void 0, function* () {
621
+ const platform = getPlatform();
622
+ switch (platform) {
623
+ case exports.Platform.ANDROID:
624
+ return checkAndroidPermissions();
625
+ case exports.Platform.IOS:
626
+ return checkIOSPermissions();
627
+ case exports.Platform.HARMONY:
628
+ return checkHarmonyPermissions();
629
+ default:
630
+ return false;
631
+ }
632
+ });
633
+ }
634
+ /**
635
+ * 请求权限
636
+ */
637
+ function requestPermissions() {
638
+ return __awaiter(this, void 0, void 0, function* () {
639
+ const platform = getPlatform();
640
+ switch (platform) {
641
+ case exports.Platform.ANDROID:
642
+ return requestAndroidPermissions();
643
+ case exports.Platform.IOS:
644
+ return requestIOSPermissions();
645
+ case exports.Platform.HARMONY:
646
+ return requestHarmonyPermissions();
647
+ default:
648
+ return false;
649
+ }
650
+ });
651
+ }
652
+ /**
653
+ * 检查安卓权限
654
+ */
655
+ function checkAndroidPermissions() {
656
+ return __awaiter(this, void 0, void 0, function* () {
657
+ return new Promise((resolve) => {
658
+ var _a;
659
+ // #ifdef APP-PLUS
660
+ const mainActivity = plus.android.runtimeMainActivity();
661
+ const PackageManager = plus.android.importClass('android.content.pm.PackageManager');
662
+ // 获取系统版本
663
+ const systemInfo = uni.getSystemInfoSync();
664
+ const osVersion = parseInt(((_a = systemInfo.system) === null || _a === void 0 ? void 0 : _a.split('.')[0]) || '0');
665
+ let permissions;
666
+ if (osVersion >= 12) {
667
+ // Android 12+ 使用新权限
668
+ permissions = [
669
+ ANDROID_PERMISSIONS.BLUETOOTH_SCAN,
670
+ ANDROID_PERMISSIONS.BLUETOOTH_CONNECT,
671
+ ANDROID_PERMISSIONS.ACCESS_FINE_LOCATION,
672
+ ];
673
+ }
674
+ else {
675
+ // Android 11 及以下使用旧权限
676
+ permissions = [
677
+ ANDROID_PERMISSIONS.BLUETOOTH,
678
+ ANDROID_PERMISSIONS.BLUETOOTH_ADMIN,
679
+ ANDROID_PERMISSIONS.ACCESS_FINE_LOCATION,
680
+ ];
681
+ }
682
+ for (const permission of permissions) {
683
+ const result = mainActivity.checkSelfPermission(permission);
684
+ if (result !== PackageManager.PERMISSION_GRANTED) {
685
+ resolve(false);
686
+ return;
687
+ }
688
+ }
689
+ resolve(true);
690
+ // #endif
691
+ // #ifndef APP-PLUS
692
+ resolve(true);
693
+ // #endif
694
+ });
695
+ });
696
+ }
697
+ /**
698
+ * 请求安卓权限
699
+ */
700
+ function requestAndroidPermissions() {
701
+ return __awaiter(this, void 0, void 0, function* () {
702
+ return new Promise((resolve) => {
703
+ var _a;
704
+ // #ifdef APP-PLUS
705
+ plus.android.runtimeMainActivity();
706
+ const systemInfo = uni.getSystemInfoSync();
707
+ const osVersion = parseInt(((_a = systemInfo.system) === null || _a === void 0 ? void 0 : _a.split('.')[0]) || '0');
708
+ let permissions;
709
+ if (osVersion >= 12) {
710
+ permissions = [
711
+ ANDROID_PERMISSIONS.BLUETOOTH_SCAN,
712
+ ANDROID_PERMISSIONS.BLUETOOTH_CONNECT,
713
+ ANDROID_PERMISSIONS.ACCESS_FINE_LOCATION,
714
+ ];
715
+ }
716
+ else {
717
+ permissions = [
718
+ ANDROID_PERMISSIONS.BLUETOOTH,
719
+ ANDROID_PERMISSIONS.BLUETOOTH_ADMIN,
720
+ ANDROID_PERMISSIONS.ACCESS_FINE_LOCATION,
721
+ ];
722
+ }
723
+ // 使用 uniapp 的权限请求API
724
+ uni.requestAndroidPermission(permissions[0], (result) => {
725
+ if (result.granted) {
726
+ resolve(true);
727
+ }
728
+ else {
729
+ resolve(false);
730
+ }
731
+ }, (error) => {
732
+ console.error('请求权限失败:', error);
733
+ resolve(false);
734
+ });
735
+ // #endif
736
+ // #ifndef APP-PLUS
737
+ resolve(true);
738
+ // #endif
739
+ });
740
+ });
741
+ }
742
+ /**
743
+ * 检查 iOS 权限
744
+ */
745
+ function checkIOSPermissions() {
746
+ return __awaiter(this, void 0, void 0, function* () {
747
+ // iOS 权限由系统自动管理
748
+ // 需要在 manifest.json 或原生工程中配置 Info.plist
749
+ return true;
750
+ });
751
+ }
752
+ /**
753
+ * 请求 iOS 权限
754
+ */
755
+ function requestIOSPermissions() {
756
+ return __awaiter(this, void 0, void 0, function* () {
757
+ // iOS 权限由系统自动管理
758
+ return true;
759
+ });
760
+ }
761
+ /**
762
+ * 检查鸿蒙权限
763
+ */
764
+ function checkHarmonyPermissions() {
765
+ return __awaiter(this, void 0, void 0, function* () {
766
+ // #ifdef HARMONY
767
+ // 鸿蒙权限检查逻辑
768
+ try {
769
+ const atManager = require('@ohos.abilityAccessCtrl').createAtManager();
770
+ const tokenId = require('@ohos.process').process.accessTokenId;
771
+ const permissions = [
772
+ HARMONY_PERMISSIONS.ACCESS_BLUETOOTH,
773
+ HARMONY_PERMISSIONS.LOCATION,
774
+ ];
775
+ for (const permission of permissions) {
776
+ const result = yield atManager.verifyAccessToken(tokenId, permission);
777
+ if (result !== 0) { // PERMISSION_GRANTED = 0
778
+ return false;
779
+ }
780
+ }
781
+ return true;
782
+ }
783
+ catch (error) {
784
+ console.error('检查鸿蒙权限失败:', error);
785
+ return false;
786
+ }
787
+ // #endif
788
+ // #ifndef HARMONY
789
+ return true;
790
+ // #endif
791
+ });
792
+ }
793
+ /**
794
+ * 请求鸿蒙权限
795
+ */
796
+ function requestHarmonyPermissions() {
797
+ return __awaiter(this, void 0, void 0, function* () {
798
+ // #ifdef HARMONY
799
+ try {
800
+ const atManager = require('@ohos.abilityAccessCtrl').createAtManager();
801
+ const context = getContext(this);
802
+ const permissions = [
803
+ HARMONY_PERMISSIONS.ACCESS_BLUETOOTH,
804
+ HARMONY_PERMISSIONS.LOCATION,
805
+ ];
806
+ const result = yield atManager.requestPermissionsFromUser(context, permissions);
807
+ return result.authResults.every((authResult) => authResult === 0);
808
+ }
809
+ catch (error) {
810
+ console.error('请求鸿蒙权限失败:', error);
811
+ return false;
812
+ }
813
+ // #endif
814
+ // #ifndef HARMONY
815
+ return true;
816
+ // #endif
817
+ });
818
+ }
819
+
820
+ /**
821
+ * UniApp 蓝牙扫描器
822
+ * 支持安卓、iOS 和鸿蒙平台
823
+ */
824
+ class UniAppScanner extends BaseScanner {
825
+ constructor() {
826
+ super(...arguments);
827
+ this.adapterStateChangeHandler = null;
828
+ }
829
+ getPlatform() {
830
+ var _a;
831
+ const systemInfo = uni.getSystemInfoSync();
832
+ const platform = ((_a = systemInfo.platform) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
833
+ if (platform === 'android') {
834
+ return exports.Platform.ANDROID;
835
+ }
836
+ else if (platform === 'ios') {
837
+ return exports.Platform.IOS;
838
+ }
839
+ else if (platform === 'harmony' || platform === 'harmonyos') {
840
+ return exports.Platform.HARMONY;
841
+ }
842
+ return exports.Platform.UNKNOWN;
843
+ }
844
+ init() {
845
+ return __awaiter(this, void 0, void 0, function* () {
846
+ return new Promise((resolve, reject) => {
847
+ // 打开蓝牙适配器
848
+ uni.openBluetoothAdapter({
849
+ success: () => {
850
+ this.initialized = true;
851
+ resolve();
852
+ },
853
+ fail: (err) => {
854
+ reject(createError(ErrorCodes.ADAPTER_NOT_AVAILABLE, `初始化蓝牙适配器失败: ${err.errMsg}`, err.errCode, err));
855
+ },
856
+ });
857
+ });
858
+ });
859
+ }
860
+ startScanInternal() {
861
+ return __awaiter(this, void 0, void 0, function* () {
862
+ return new Promise((resolve, reject) => {
863
+ const scanOptions = {
864
+ allowDuplicatesKey: this.options.allowDuplicates || false,
865
+ success: () => {
866
+ // 监听设备发现
867
+ this.startDeviceDiscovery();
868
+ resolve();
869
+ },
870
+ fail: (err) => {
871
+ reject(Errors.scanFailed(err.errMsg));
872
+ },
873
+ };
874
+ // 添加服务UUID过滤
875
+ if (this.options.services && this.options.services.length > 0) {
876
+ scanOptions.services = this.options.services;
877
+ }
878
+ uni.startBluetoothDevicesDiscovery(scanOptions);
879
+ });
880
+ });
881
+ }
882
+ stopScanInternal() {
883
+ return __awaiter(this, void 0, void 0, function* () {
884
+ return new Promise((resolve, reject) => {
885
+ uni.stopBluetoothDevicesDiscovery({
886
+ success: () => {
887
+ this.stopDeviceDiscovery();
888
+ resolve();
889
+ },
890
+ fail: (err) => {
891
+ reject(Errors.scanFailed(err.errMsg));
892
+ },
893
+ });
894
+ });
895
+ });
896
+ }
897
+ checkPermissions() {
898
+ return __awaiter(this, void 0, void 0, function* () {
899
+ return checkPermissions();
900
+ });
901
+ }
902
+ requestPermissions() {
903
+ return __awaiter(this, void 0, void 0, function* () {
904
+ return requestPermissions();
905
+ });
906
+ }
907
+ onAdapterStateChange(callback) {
908
+ this.adapterStateListeners.push(callback);
909
+ // 如果还没有监听,开始监听
910
+ if (!this.adapterStateChangeHandler) {
911
+ this.adapterStateChangeHandler = (res) => {
912
+ this.emitAdapterStateChange({
913
+ available: res.available,
914
+ discovering: res.discovering,
915
+ });
916
+ };
917
+ uni.onBluetoothAdapterStateChange(this.adapterStateChangeHandler);
918
+ }
919
+ }
920
+ destroy() {
921
+ super.destroy();
922
+ // 移除适配器状态监听
923
+ if (this.adapterStateChangeHandler) {
924
+ uni.offBluetoothAdapterStateChange(this.adapterStateChangeHandler);
925
+ this.adapterStateChangeHandler = null;
926
+ }
927
+ // 关闭蓝牙适配器
928
+ uni.closeBluetoothAdapter({
929
+ success: () => {
930
+ console.log('蓝牙适配器已关闭');
931
+ },
932
+ fail: (err) => {
933
+ console.error('关闭蓝牙适配器失败:', err);
934
+ },
935
+ });
936
+ }
937
+ /**
938
+ * 开始监听设备发现
939
+ */
940
+ startDeviceDiscovery() {
941
+ uni.onBluetoothDeviceFound((res) => {
942
+ const devices = res.devices || [];
943
+ devices.forEach((device) => {
944
+ this.handleDeviceFound(device);
945
+ });
946
+ });
947
+ }
948
+ /**
949
+ * 停止监听设备发现
950
+ */
951
+ stopDeviceDiscovery() {
952
+ uni.offBluetoothDeviceFound();
953
+ }
954
+ /**
955
+ * 获取蓝牙适配器状态
956
+ */
957
+ getAdapterState() {
958
+ return __awaiter(this, void 0, void 0, function* () {
959
+ return new Promise((resolve, reject) => {
960
+ uni.getBluetoothAdapterState({
961
+ success: (res) => {
962
+ resolve({
963
+ available: res.available,
964
+ discovering: res.discovering,
965
+ });
966
+ },
967
+ fail: (err) => {
968
+ reject(Errors.adapterNotAvailable());
969
+ },
970
+ });
971
+ });
972
+ });
973
+ }
974
+ }
975
+
976
+ /**
977
+ * Android 原生蓝牙扫描器
978
+ * 使用 uni-app 的 Native.js 调用 Android 原生 API
979
+ */
980
+ class AndroidNativeScanner extends BaseScanner {
981
+ constructor() {
982
+ super(...arguments);
983
+ this.bluetoothAdapter = null;
984
+ this.bluetoothLeScanner = null;
985
+ this.scanCallback = null;
986
+ this.adapterStateReceiver = null;
987
+ this.legacyScanCallback = null;
988
+ }
989
+ getPlatform() {
990
+ return exports.Platform.ANDROID;
991
+ }
992
+ init() {
993
+ return __awaiter(this, void 0, void 0, function* () {
994
+ return new Promise((resolve, reject) => {
995
+ try {
996
+ // #ifdef APP-PLUS
997
+ const mainActivity = plus.android.runtimeMainActivity();
998
+ const BluetoothManager = plus.android.importClass('android.bluetooth.BluetoothManager');
999
+ const bluetoothManager = mainActivity.getSystemService('bluetooth');
1000
+ this.bluetoothAdapter = bluetoothManager.getAdapter();
1001
+ if (!this.bluetoothAdapter) {
1002
+ reject(Errors.adapterNotAvailable());
1003
+ return;
1004
+ }
1005
+ if (!this.bluetoothAdapter.isEnabled()) {
1006
+ reject(Errors.bluetoothDisabled());
1007
+ return;
1008
+ }
1009
+ this.initialized = true;
1010
+ resolve();
1011
+ // #endif
1012
+ // #ifndef APP-PLUS
1013
+ reject(createError(ErrorCodes.UNSUPPORTED_PLATFORM, '非 APP 环境不支持原生 Android 扫描'));
1014
+ // #endif
1015
+ }
1016
+ catch (error) {
1017
+ reject(handlePlatformError(error, 'android'));
1018
+ }
1019
+ });
1020
+ });
1021
+ }
1022
+ startScanInternal() {
1023
+ return __awaiter(this, void 0, void 0, function* () {
1024
+ return new Promise((resolve, reject) => {
1025
+ var _a;
1026
+ try {
1027
+ // #ifdef APP-PLUS
1028
+ const systemInfo = uni.getSystemInfoSync();
1029
+ const osVersion = parseInt(((_a = systemInfo.system) === null || _a === void 0 ? void 0 : _a.split('.')[0]) || '0');
1030
+ if (osVersion >= 21 && this.bluetoothAdapter.getBluetoothLeScanner) {
1031
+ // Android 5.0+ 使用新的扫描 API
1032
+ this.startNewScanAPI(resolve, reject);
1033
+ }
1034
+ else {
1035
+ // 旧版扫描 API
1036
+ this.startLegacyScan(resolve, reject);
1037
+ }
1038
+ // #endif
1039
+ // #ifndef APP-PLUS
1040
+ reject(Errors.unsupportedPlatform());
1041
+ // #endif
1042
+ }
1043
+ catch (error) {
1044
+ reject(handlePlatformError(error, 'android'));
1045
+ }
1046
+ });
1047
+ });
1048
+ }
1049
+ stopScanInternal() {
1050
+ return __awaiter(this, void 0, void 0, function* () {
1051
+ return new Promise((resolve, reject) => {
1052
+ try {
1053
+ // #ifdef APP-PLUS
1054
+ if (this.bluetoothLeScanner && this.scanCallback) {
1055
+ this.bluetoothLeScanner.stopScan(this.scanCallback);
1056
+ }
1057
+ else if (this.bluetoothAdapter) {
1058
+ this.bluetoothAdapter.stopLeScan(this.legacyScanCallback);
1059
+ }
1060
+ resolve();
1061
+ // #endif
1062
+ // #ifndef APP-PLUS
1063
+ reject(Errors.unsupportedPlatform());
1064
+ // #endif
1065
+ }
1066
+ catch (error) {
1067
+ reject(handlePlatformError(error, 'android'));
1068
+ }
1069
+ });
1070
+ });
1071
+ }
1072
+ checkPermissions() {
1073
+ return __awaiter(this, void 0, void 0, function* () {
1074
+ var _a;
1075
+ // #ifdef APP-PLUS
1076
+ const mainActivity = plus.android.runtimeMainActivity();
1077
+ const PackageManager = plus.android.importClass('android.content.pm.PackageManager');
1078
+ const systemInfo = uni.getSystemInfoSync();
1079
+ const osVersion = parseInt(((_a = systemInfo.system) === null || _a === void 0 ? void 0 : _a.split('.')[0]) || '0');
1080
+ let permissions;
1081
+ if (osVersion >= 12) {
1082
+ permissions = [
1083
+ 'android.permission.BLUETOOTH_SCAN',
1084
+ 'android.permission.BLUETOOTH_CONNECT',
1085
+ 'android.permission.ACCESS_FINE_LOCATION',
1086
+ ];
1087
+ }
1088
+ else {
1089
+ permissions = [
1090
+ 'android.permission.BLUETOOTH',
1091
+ 'android.permission.BLUETOOTH_ADMIN',
1092
+ 'android.permission.ACCESS_FINE_LOCATION',
1093
+ ];
1094
+ }
1095
+ for (const permission of permissions) {
1096
+ const result = mainActivity.checkSelfPermission(permission);
1097
+ if (result !== PackageManager.PERMISSION_GRANTED) {
1098
+ return false;
1099
+ }
1100
+ }
1101
+ return true;
1102
+ // #endif
1103
+ });
1104
+ }
1105
+ requestPermissions() {
1106
+ return __awaiter(this, void 0, void 0, function* () {
1107
+ // #ifdef APP-PLUS
1108
+ return new Promise((resolve) => {
1109
+ var _a;
1110
+ const systemInfo = uni.getSystemInfoSync();
1111
+ const osVersion = parseInt(((_a = systemInfo.system) === null || _a === void 0 ? void 0 : _a.split('.')[0]) || '0');
1112
+ let permissions;
1113
+ if (osVersion >= 12) {
1114
+ permissions = [
1115
+ 'android.permission.BLUETOOTH_SCAN',
1116
+ 'android.permission.BLUETOOTH_CONNECT',
1117
+ 'android.permission.ACCESS_FINE_LOCATION',
1118
+ ];
1119
+ }
1120
+ else {
1121
+ permissions = [
1122
+ 'android.permission.BLUETOOTH',
1123
+ 'android.permission.BLUETOOTH_ADMIN',
1124
+ 'android.permission.ACCESS_FINE_LOCATION',
1125
+ ];
1126
+ }
1127
+ uni.requestAndroidPermission(permissions[0], (result) => {
1128
+ resolve(result.granted);
1129
+ }, () => {
1130
+ resolve(false);
1131
+ });
1132
+ });
1133
+ // #endif
1134
+ });
1135
+ }
1136
+ onAdapterStateChange(callback) {
1137
+ this.adapterStateListeners.push(callback);
1138
+ // #ifdef APP-PLUS
1139
+ if (!this.adapterStateReceiver) {
1140
+ plus.android.runtimeMainActivity();
1141
+ const IntentFilter = plus.android.importClass('android.content.IntentFilter');
1142
+ const BluetoothAdapter = plus.android.importClass('android.bluetooth.BluetoothAdapter');
1143
+ const filter = new IntentFilter();
1144
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
1145
+ // 这里简化处理,实际应该创建 BroadcastReceiver
1146
+ // 由于 Native.js 限制,建议使用 uni-app 的标准 API 监听状态
1147
+ }
1148
+ // #endif
1149
+ }
1150
+ destroy() {
1151
+ super.destroy();
1152
+ this.bluetoothAdapter = null;
1153
+ this.bluetoothLeScanner = null;
1154
+ this.scanCallback = null;
1155
+ }
1156
+ /**
1157
+ * 使用新版扫描 API (Android 5.0+)
1158
+ */
1159
+ startNewScanAPI(resolve, reject) {
1160
+ var _a;
1161
+ // #ifdef APP-PLUS
1162
+ try {
1163
+ const ScanSettings = plus.android.importClass('android.bluetooth.le.ScanSettings');
1164
+ const ScanFilter = plus.android.importClass('android.bluetooth.le.ScanFilter');
1165
+ const ScanCallback = plus.android.importClass('android.bluetooth.le.ScanCallback');
1166
+ this.bluetoothLeScanner = this.bluetoothAdapter.getBluetoothLeScanner();
1167
+ // 构建扫描设置
1168
+ const builder = new ScanSettings.Builder();
1169
+ // 设置扫描模式
1170
+ const scanMode = ((_a = this.platformConfig.android) === null || _a === void 0 ? void 0 : _a.scanMode) || ScanSettings.SCAN_MODE_LOW_LATENCY;
1171
+ builder.setScanMode(scanMode);
1172
+ const settings = builder.build();
1173
+ // 构建扫描过滤器
1174
+ const filters = [];
1175
+ if (this.options.services && this.options.services.length > 0) {
1176
+ // 可以添加服务 UUID 过滤
1177
+ }
1178
+ // 创建扫描回调
1179
+ const self = this;
1180
+ this.scanCallback = new ScanCallback({
1181
+ onScanResult: (callbackType, result) => {
1182
+ const device = result.getDevice();
1183
+ const rssi = result.getRssi();
1184
+ const scanRecord = result.getScanRecord();
1185
+ self.handleDeviceFound({
1186
+ deviceId: device.getAddress(),
1187
+ name: device.getName(),
1188
+ RSSI: rssi,
1189
+ advertisData: scanRecord ? scanRecord.getBytes() : null,
1190
+ });
1191
+ },
1192
+ onBatchScanResults: (results) => {
1193
+ results.forEach((result) => {
1194
+ this.scanCallback.onScanResult(0, result);
1195
+ });
1196
+ },
1197
+ onScanFailed: (errorCode) => {
1198
+ reject(Errors.scanFailed(`错误码: ${errorCode}`));
1199
+ },
1200
+ });
1201
+ this.bluetoothLeScanner.startScan(filters, settings, this.scanCallback);
1202
+ resolve();
1203
+ }
1204
+ catch (error) {
1205
+ reject(handlePlatformError(error, 'android'));
1206
+ }
1207
+ // #endif
1208
+ }
1209
+ /**
1210
+ * 使用旧版扫描 API
1211
+ */
1212
+ startLegacyScan(resolve, reject) {
1213
+ // #ifdef APP-PLUS
1214
+ try {
1215
+ const self = this;
1216
+ this.legacyScanCallback = new plus.android.implements('android.bluetooth.BluetoothAdapter.LeScanCallback', {
1217
+ onLeScan: (device, rssi, scanRecord) => {
1218
+ self.handleDeviceFound({
1219
+ deviceId: device.getAddress(),
1220
+ name: device.getName(),
1221
+ RSSI: rssi,
1222
+ advertisData: scanRecord,
1223
+ });
1224
+ },
1225
+ });
1226
+ let serviceUuids = null;
1227
+ if (this.options.services && this.options.services.length > 0) {
1228
+ serviceUuids = this.options.services;
1229
+ }
1230
+ const started = this.bluetoothAdapter.startLeScan(serviceUuids, this.legacyScanCallback);
1231
+ if (started) {
1232
+ resolve();
1233
+ }
1234
+ else {
1235
+ reject(Errors.scanFailed('启动扫描失败'));
1236
+ }
1237
+ }
1238
+ catch (error) {
1239
+ reject(handlePlatformError(error, 'android'));
1240
+ }
1241
+ // #endif
1242
+ }
1243
+ }
1244
+
1245
+ /**
1246
+ * iOS 原生蓝牙扫描器
1247
+ * 使用 uni-app 的 Native.js 调用 iOS CoreBluetooth API
1248
+ */
1249
+ class IOSNativeScanner extends BaseScanner {
1250
+ constructor() {
1251
+ super(...arguments);
1252
+ this.centralManager = null;
1253
+ this.delegate = null;
1254
+ }
1255
+ getPlatform() {
1256
+ return exports.Platform.IOS;
1257
+ }
1258
+ init() {
1259
+ return __awaiter(this, void 0, void 0, function* () {
1260
+ return new Promise((resolve, reject) => {
1261
+ var _a;
1262
+ try {
1263
+ // #ifdef APP-PLUS
1264
+ // 导入 iOS CoreBluetooth 框架
1265
+ const CBCentralManager = plus.ios.importClass('CBCentralManager');
1266
+ const CBUUID = plus.ios.importClass('CBUUID');
1267
+ const dispatch_queue_attr_make_with_qos_class = plus.ios.importClass('dispatch_queue_attr_make_with_qos_class');
1268
+ const dispatch_queue_create = plus.ios.importClass('dispatch_queue_create');
1269
+ // 创建队列
1270
+ const queue = dispatch_queue_create('com.ble.scanner', null);
1271
+ // 创建中央管理器
1272
+ this.centralManager = new CBCentralManager({
1273
+ queue: queue,
1274
+ options: {
1275
+ 'CBCentralManagerOptionShowPowerAlertKey': true,
1276
+ 'CBCentralManagerOptionRestoreIdentifierKey': (_a = this.platformConfig.ios) === null || _a === void 0 ? void 0 : _a.restoreIdentifier,
1277
+ },
1278
+ });
1279
+ if (!this.centralManager) {
1280
+ reject(Errors.adapterNotAvailable());
1281
+ return;
1282
+ }
1283
+ // 设置委托
1284
+ const self = this;
1285
+ this.delegate = plus.ios.implements('CBCentralManagerDelegate', {
1286
+ centralManagerDidUpdateState: (central) => {
1287
+ const state = central.state();
1288
+ // CBManagerStatePoweredOn = 5
1289
+ if (state === 5) {
1290
+ self.initialized = true;
1291
+ resolve();
1292
+ }
1293
+ else if (state === 4) { // CBManagerStatePoweredOff
1294
+ reject(Errors.bluetoothDisabled());
1295
+ }
1296
+ else {
1297
+ reject(createError(ErrorCodes.ADAPTER_NOT_AVAILABLE, `蓝牙适配器状态异常: ${state}`));
1298
+ }
1299
+ },
1300
+ centralManagerDidDiscoverPeripheralAdvertisementDataRSSI: (central, peripheral, advertisementData, RSSI) => {
1301
+ self.handlePeripheral(peripheral, advertisementData, RSSI);
1302
+ },
1303
+ });
1304
+ this.centralManager.setDelegate(this.delegate);
1305
+ // 检查当前状态
1306
+ const currentState = this.centralManager.state();
1307
+ if (currentState === 5) {
1308
+ this.initialized = true;
1309
+ resolve();
1310
+ }
1311
+ // 否则等待委托回调
1312
+ // #endif
1313
+ // #ifndef APP-PLUS
1314
+ reject(createError(ErrorCodes.UNSUPPORTED_PLATFORM, '非 APP 环境不支持原生 iOS 扫描'));
1315
+ // #endif
1316
+ }
1317
+ catch (error) {
1318
+ reject(handlePlatformError(error, 'ios'));
1319
+ }
1320
+ });
1321
+ });
1322
+ }
1323
+ startScanInternal() {
1324
+ return __awaiter(this, void 0, void 0, function* () {
1325
+ return new Promise((resolve, reject) => {
1326
+ try {
1327
+ // #ifdef APP-PLUS
1328
+ const CBUUID = plus.ios.importClass('CBUUID');
1329
+ const NSArray = plus.ios.importClass('NSArray');
1330
+ const NSMutableDictionary = plus.ios.importClass('NSMutableDictionary');
1331
+ // 构建服务 UUID 列表
1332
+ let serviceUUIDs = null;
1333
+ if (this.options.services && this.options.services.length > 0) {
1334
+ const uuids = [];
1335
+ this.options.services.forEach((uuid) => {
1336
+ const cbUuid = CBUUID.UUIDWithString(uuid);
1337
+ uuids.push(cbUuid);
1338
+ });
1339
+ serviceUUIDs = NSArray.arrayWithArray(uuids);
1340
+ }
1341
+ // 构建扫描选项
1342
+ const options = NSMutableDictionary.dictionary();
1343
+ options.setObjectForKey(this.options.allowDuplicates ? 1 : 0, 'CBCentralManagerScanOptionAllowDuplicatesKey');
1344
+ // 开始扫描
1345
+ this.centralManager.scanForPeripheralsWithServicesOptions(serviceUUIDs, options);
1346
+ resolve();
1347
+ // #endif
1348
+ // #ifndef APP-PLUS
1349
+ reject(Errors.unsupportedPlatform());
1350
+ // #endif
1351
+ }
1352
+ catch (error) {
1353
+ reject(handlePlatformError(error, 'ios'));
1354
+ }
1355
+ });
1356
+ });
1357
+ }
1358
+ stopScanInternal() {
1359
+ return __awaiter(this, void 0, void 0, function* () {
1360
+ return new Promise((resolve, reject) => {
1361
+ try {
1362
+ // #ifdef APP-PLUS
1363
+ if (this.centralManager) {
1364
+ this.centralManager.stopScan();
1365
+ }
1366
+ resolve();
1367
+ // #endif
1368
+ // #ifndef APP-PLUS
1369
+ reject(Errors.unsupportedPlatform());
1370
+ // #endif
1371
+ }
1372
+ catch (error) {
1373
+ reject(handlePlatformError(error, 'ios'));
1374
+ }
1375
+ });
1376
+ });
1377
+ }
1378
+ checkPermissions() {
1379
+ return __awaiter(this, void 0, void 0, function* () {
1380
+ // iOS 权限由系统自动管理
1381
+ // 需要在原生工程的 Info.plist 中配置 NSBluetoothAlwaysUsageDescription
1382
+ return true;
1383
+ });
1384
+ }
1385
+ requestPermissions() {
1386
+ return __awaiter(this, void 0, void 0, function* () {
1387
+ // iOS 权限由系统自动管理
1388
+ return true;
1389
+ });
1390
+ }
1391
+ onAdapterStateChange(callback) {
1392
+ this.adapterStateListeners.push(callback);
1393
+ // 委托中已处理状态变化
1394
+ }
1395
+ destroy() {
1396
+ super.destroy();
1397
+ // #ifdef APP-PLUS
1398
+ if (this.centralManager) {
1399
+ this.centralManager.stopScan();
1400
+ plus.ios.deleteObject(this.centralManager);
1401
+ }
1402
+ if (this.delegate) {
1403
+ plus.ios.deleteObject(this.delegate);
1404
+ }
1405
+ // #endif
1406
+ this.centralManager = null;
1407
+ this.delegate = null;
1408
+ }
1409
+ /**
1410
+ * 处理发现的外设
1411
+ */
1412
+ handlePeripheral(peripheral, advertisementData, RSSI) {
1413
+ try {
1414
+ // #ifdef APP-PLUS
1415
+ const deviceId = peripheral.identifier().UUIDString();
1416
+ const name = peripheral.name();
1417
+ // 解析广播数据
1418
+ const localName = advertisementData.objectForKey('kCBAdvDataLocalName');
1419
+ const serviceUUIDs = advertisementData.objectForKey('kCBAdvDataServiceUUIDs');
1420
+ const manufacturerData = advertisementData.objectForKey('kCBAdvDataManufacturerData');
1421
+ const isConnectable = advertisementData.objectForKey('kCBAdvDataIsConnectable');
1422
+ const txPowerLevel = advertisementData.objectForKey('kCBAdvDataTxPowerLevel');
1423
+ // 转换服务 UUID
1424
+ const serviceUuids = [];
1425
+ if (serviceUUIDs) {
1426
+ const count = serviceUUIDs.count();
1427
+ for (let i = 0; i < count; i++) {
1428
+ const uuid = serviceUUIDs.objectAtIndex(i).UUIDString();
1429
+ serviceUuids.push(uuid);
1430
+ }
1431
+ }
1432
+ // 转换制造商数据
1433
+ let manufacturerDataBuffer;
1434
+ if (manufacturerData) {
1435
+ const length = manufacturerData.length();
1436
+ const bytes = new Uint8Array(length);
1437
+ manufacturerData.getBytes(bytes);
1438
+ manufacturerDataBuffer = bytes.buffer;
1439
+ }
1440
+ this.handleDeviceFound({
1441
+ deviceId,
1442
+ name: name || localName,
1443
+ RSSI,
1444
+ advertisData: manufacturerDataBuffer,
1445
+ serviceUuids,
1446
+ localName,
1447
+ isConnectable,
1448
+ txPowerLevel,
1449
+ });
1450
+ // #endif
1451
+ }
1452
+ catch (error) {
1453
+ console.error('处理外设数据失败:', error);
1454
+ }
1455
+ }
1456
+ /**
1457
+ * 获取 iOS 蓝牙适配器状态
1458
+ */
1459
+ getAdapterState() {
1460
+ return __awaiter(this, void 0, void 0, function* () {
1461
+ return new Promise((resolve, reject) => {
1462
+ // #ifdef APP-PLUS
1463
+ try {
1464
+ const state = this.centralManager.state();
1465
+ // CBManagerStatePoweredOn = 5
1466
+ resolve({
1467
+ available: state === 5,
1468
+ discovering: this.state === 'scanning',
1469
+ });
1470
+ }
1471
+ catch (error) {
1472
+ reject(handlePlatformError(error, 'ios'));
1473
+ }
1474
+ // #endif
1475
+ // #ifndef APP-PLUS
1476
+ reject(Errors.unsupportedPlatform());
1477
+ // #endif
1478
+ });
1479
+ });
1480
+ }
1481
+ }
1482
+
1483
+ /**
1484
+ * 鸿蒙原生蓝牙扫描器
1485
+ * 使用鸿蒙原生 API 进行蓝牙扫描
1486
+ */
1487
+ class HarmonyNativeScanner extends BaseScanner {
1488
+ constructor() {
1489
+ super(...arguments);
1490
+ this.bluetoothManager = null;
1491
+ this.bleScanner = null;
1492
+ this.scanCallback = null;
1493
+ }
1494
+ getPlatform() {
1495
+ return exports.Platform.HARMONY;
1496
+ }
1497
+ init() {
1498
+ return __awaiter(this, void 0, void 0, function* () {
1499
+ return new Promise((resolve, reject) => {
1500
+ try {
1501
+ // #ifdef HARMONY
1502
+ // 导入鸿蒙蓝牙模块
1503
+ const bluetooth = require('@ohos.bluetooth.ble');
1504
+ // 获取蓝牙管理器
1505
+ this.bluetoothManager = bluetooth.BLE;
1506
+ if (!this.bluetoothManager) {
1507
+ reject(Errors.adapterNotAvailable());
1508
+ return;
1509
+ }
1510
+ // 检查蓝牙是否开启
1511
+ const state = this.bluetoothManager.getState();
1512
+ if (state !== 2) { // STATE_ON = 2
1513
+ reject(Errors.bluetoothDisabled());
1514
+ return;
1515
+ }
1516
+ this.initialized = true;
1517
+ resolve();
1518
+ // #endif
1519
+ // #ifndef HARMONY
1520
+ reject(createError(ErrorCodes.UNSUPPORTED_PLATFORM, '非鸿蒙环境不支持原生鸿蒙扫描'));
1521
+ // #endif
1522
+ }
1523
+ catch (error) {
1524
+ reject(handlePlatformError(error, 'harmony'));
1525
+ }
1526
+ });
1527
+ });
1528
+ }
1529
+ startScanInternal() {
1530
+ return __awaiter(this, void 0, void 0, function* () {
1531
+ return new Promise((resolve, reject) => {
1532
+ try {
1533
+ // #ifdef HARMONY
1534
+ const bluetooth = require('@ohos.bluetooth.ble');
1535
+ // 构建扫描过滤器
1536
+ const filters = [];
1537
+ if (this.options.services && this.options.services.length > 0) {
1538
+ this.options.services.forEach((uuid) => {
1539
+ const filter = {
1540
+ serviceUuid: uuid,
1541
+ };
1542
+ filters.push(filter);
1543
+ });
1544
+ }
1545
+ if (this.options.nameFilter) {
1546
+ const names = Array.isArray(this.options.nameFilter)
1547
+ ? this.options.nameFilter
1548
+ : [this.options.nameFilter];
1549
+ names.forEach((name) => {
1550
+ if (typeof name === 'string') {
1551
+ filters.push({ deviceName: name });
1552
+ }
1553
+ });
1554
+ }
1555
+ // 构建扫描配置
1556
+ const scanOptions = {
1557
+ interval: 0,
1558
+ dutyMode: bluetooth.ScanDuty.SCAN_MODE_LOW_LATENCY,
1559
+ matchMode: bluetooth.MatchMode.MATCH_MODE_AGGRESSIVE,
1560
+ };
1561
+ // 创建扫描回调
1562
+ const self = this;
1563
+ this.scanCallback = {
1564
+ onScanResult: (result) => {
1565
+ const device = result.device;
1566
+ const data = result.data;
1567
+ const rssi = result.rssi;
1568
+ self.handleDeviceFound({
1569
+ deviceId: device.deviceId,
1570
+ name: device.deviceName,
1571
+ RSSI: rssi,
1572
+ advertisData: data,
1573
+ serviceUuids: result.serviceUuids,
1574
+ });
1575
+ },
1576
+ onScanFailed: (errorCode) => {
1577
+ console.error('扫描失败:', errorCode);
1578
+ },
1579
+ };
1580
+ // 开始扫描
1581
+ this.bluetoothManager.startBLEScan(filters, scanOptions, this.scanCallback);
1582
+ resolve();
1583
+ // #endif
1584
+ // #ifndef HARMONY
1585
+ reject(Errors.unsupportedPlatform());
1586
+ // #endif
1587
+ }
1588
+ catch (error) {
1589
+ reject(handlePlatformError(error, 'harmony'));
1590
+ }
1591
+ });
1592
+ });
1593
+ }
1594
+ stopScanInternal() {
1595
+ return __awaiter(this, void 0, void 0, function* () {
1596
+ return new Promise((resolve, reject) => {
1597
+ try {
1598
+ // #ifdef HARMONY
1599
+ if (this.bluetoothManager) {
1600
+ this.bluetoothManager.stopBLEScan();
1601
+ }
1602
+ resolve();
1603
+ // #endif
1604
+ // #ifndef HARMONY
1605
+ reject(Errors.unsupportedPlatform());
1606
+ // #endif
1607
+ }
1608
+ catch (error) {
1609
+ reject(handlePlatformError(error, 'harmony'));
1610
+ }
1611
+ });
1612
+ });
1613
+ }
1614
+ checkPermissions() {
1615
+ return __awaiter(this, void 0, void 0, function* () {
1616
+ // #ifdef HARMONY
1617
+ try {
1618
+ const atManager = require('@ohos.abilityAccessCtrl').createAtManager();
1619
+ const tokenId = require('@ohos.process').process.accessTokenId;
1620
+ const permissions = [
1621
+ 'ohos.permission.ACCESS_BLUETOOTH',
1622
+ 'ohos.permission.LOCATION',
1623
+ ];
1624
+ for (const permission of permissions) {
1625
+ const result = yield atManager.verifyAccessToken(tokenId, permission);
1626
+ if (result !== 0) {
1627
+ return false;
1628
+ }
1629
+ }
1630
+ return true;
1631
+ }
1632
+ catch (error) {
1633
+ console.error('检查权限失败:', error);
1634
+ return false;
1635
+ }
1636
+ // #endif
1637
+ // #ifndef HARMONY
1638
+ return false;
1639
+ // #endif
1640
+ });
1641
+ }
1642
+ requestPermissions() {
1643
+ return __awaiter(this, void 0, void 0, function* () {
1644
+ // #ifdef HARMONY
1645
+ try {
1646
+ const atManager = require('@ohos.abilityAccessCtrl').createAtManager();
1647
+ const context = getContext(this);
1648
+ const permissions = [
1649
+ 'ohos.permission.ACCESS_BLUETOOTH',
1650
+ 'ohos.permission.LOCATION',
1651
+ ];
1652
+ const result = yield atManager.requestPermissionsFromUser(context, permissions);
1653
+ return result.authResults.every((authResult) => authResult === 0);
1654
+ }
1655
+ catch (error) {
1656
+ console.error('请求权限失败:', error);
1657
+ return false;
1658
+ }
1659
+ // #endif
1660
+ // #ifndef HARMONY
1661
+ return false;
1662
+ // #endif
1663
+ });
1664
+ }
1665
+ onAdapterStateChange(callback) {
1666
+ this.adapterStateListeners.push(callback);
1667
+ // #ifdef HARMONY
1668
+ try {
1669
+ const bluetooth = require('@ohos.bluetooth.ble');
1670
+ // 监听蓝牙状态变化
1671
+ bluetooth.on('stateChange', (data) => {
1672
+ this.emitAdapterStateChange({
1673
+ available: data.state === 2, // STATE_ON = 2
1674
+ discovering: this.state === 'scanning',
1675
+ });
1676
+ });
1677
+ }
1678
+ catch (error) {
1679
+ console.error('监听状态变化失败:', error);
1680
+ }
1681
+ // #endif
1682
+ }
1683
+ destroy() {
1684
+ super.destroy();
1685
+ // #ifdef HARMONY
1686
+ try {
1687
+ const bluetooth = require('@ohos.bluetooth.ble');
1688
+ // 停止扫描
1689
+ if (this.bluetoothManager) {
1690
+ this.bluetoothManager.stopBLEScan();
1691
+ }
1692
+ // 移除状态监听
1693
+ bluetooth.off('stateChange');
1694
+ }
1695
+ catch (error) {
1696
+ console.error('销毁失败:', error);
1697
+ }
1698
+ // #endif
1699
+ this.bluetoothManager = null;
1700
+ this.scanCallback = null;
1701
+ }
1702
+ /**
1703
+ * 获取鸿蒙蓝牙适配器状态
1704
+ */
1705
+ getAdapterState() {
1706
+ return __awaiter(this, void 0, void 0, function* () {
1707
+ return new Promise((resolve, reject) => {
1708
+ // #ifdef HARMONY
1709
+ try {
1710
+ const state = this.bluetoothManager.getState();
1711
+ resolve({
1712
+ available: state === 2,
1713
+ discovering: this.state === 'scanning',
1714
+ });
1715
+ }
1716
+ catch (error) {
1717
+ reject(handlePlatformError(error, 'harmony'));
1718
+ }
1719
+ // #endif
1720
+ // #ifndef HARMONY
1721
+ reject(Errors.unsupportedPlatform());
1722
+ // #endif
1723
+ });
1724
+ });
1725
+ }
1726
+ }
1727
+
1728
+ /**
1729
+ * 创建蓝牙扫描器
1730
+ * @param options 创建选项
1731
+ * @returns 蓝牙扫描器实例
1732
+ */
1733
+ function createScanner(options = {}) {
1734
+ const { type = 'auto', platformConfig = {} } = options;
1735
+ const platform = getPlatform();
1736
+ const app = isApp();
1737
+ // 根据类型和平台选择合适的扫描器
1738
+ if (type === 'uniapp' || (type === 'auto' && !app)) {
1739
+ // 使用 UniApp 标准 API
1740
+ const scanner = new UniAppScanner();
1741
+ Object.assign(scanner, { platformConfig });
1742
+ return scanner;
1743
+ }
1744
+ if (type === 'native' || type === 'auto') {
1745
+ // 使用原生 API
1746
+ switch (platform) {
1747
+ case exports.Platform.ANDROID:
1748
+ const androidScanner = new AndroidNativeScanner();
1749
+ Object.assign(androidScanner, { platformConfig });
1750
+ return androidScanner;
1751
+ case exports.Platform.IOS:
1752
+ const iosScanner = new IOSNativeScanner();
1753
+ Object.assign(iosScanner, { platformConfig });
1754
+ return iosScanner;
1755
+ case exports.Platform.HARMONY:
1756
+ const harmonyScanner = new HarmonyNativeScanner();
1757
+ Object.assign(harmonyScanner, { platformConfig });
1758
+ return harmonyScanner;
1759
+ default:
1760
+ // 未知平台使用 UniApp API
1761
+ const defaultScanner = new UniAppScanner();
1762
+ Object.assign(defaultScanner, { platformConfig });
1763
+ return defaultScanner;
1764
+ }
1765
+ }
1766
+ // 默认使用 UniApp API
1767
+ const defaultScanner = new UniAppScanner();
1768
+ Object.assign(defaultScanner, { platformConfig });
1769
+ return defaultScanner;
1770
+ }
1771
+ /**
1772
+ * 创建 UniApp 扫描器
1773
+ * 使用 UniApp 标准蓝牙 API,兼容所有平台
1774
+ */
1775
+ function createUniAppScanner(platformConfig) {
1776
+ return createScanner({ type: 'uniapp', platformConfig });
1777
+ }
1778
+ /**
1779
+ * 创建原生扫描器
1780
+ * 使用平台原生 API,功能更强大但需要特定条件
1781
+ */
1782
+ function createNativeScanner(platformConfig) {
1783
+ return createScanner({ type: 'native', platformConfig });
1784
+ }
1785
+ /**
1786
+ * 检查当前环境是否支持蓝牙
1787
+ */
1788
+ function isBluetoothSupported() {
1789
+ // #ifdef APP-PLUS
1790
+ return true;
1791
+ }
1792
+
1793
+ // 导出枚举
1794
+
1795
+ exports.AndroidNativeScanner = AndroidNativeScanner;
1796
+ exports.BaseScanner = BaseScanner;
1797
+ exports.ErrorCodes = ErrorCodes;
1798
+ exports.Errors = Errors;
1799
+ exports.HarmonyNativeScanner = HarmonyNativeScanner;
1800
+ exports.IOSNativeScanner = IOSNativeScanner;
1801
+ exports.UniAppScanner = UniAppScanner;
1802
+ exports.arrayBufferToBase64 = arrayBufferToBase64;
1803
+ exports.base64ToArrayBuffer = base64ToArrayBuffer;
1804
+ exports.checkPermissions = checkPermissions;
1805
+ exports.createError = createError;
1806
+ exports.createNativeScanner = createNativeScanner;
1807
+ exports.createScanner = createScanner;
1808
+ exports.createUniAppScanner = createUniAppScanner;
1809
+ exports.default = createScanner;
1810
+ exports.formatUUID = formatUUID;
1811
+ exports.getPlatform = getPlatform;
1812
+ exports.getPlatformName = getPlatformName;
1813
+ exports.isApp = isApp;
1814
+ exports.isBluetoothSupported = isBluetoothSupported;
1815
+ exports.isPlatform = isPlatform;
1816
+ exports.matchUUID = matchUUID;
1817
+ exports.parseAdvertisementData = parseAdvertisementData;
1818
+ exports.requestPermissions = requestPermissions;