@capacitor-community/bluetooth-le 8.0.0 → 8.0.2
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/CapacitorCommunityBluetoothLe.podspec +17 -17
- package/LICENSE +21 -21
- package/Package.swift +27 -27
- package/README.md +4 -2
- package/android/build.gradle +73 -73
- package/android/src/main/AndroidManifest.xml +22 -22
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/BluetoothLe.kt +1094 -1094
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Conversion.kt +51 -51
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Device.kt +771 -771
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/DeviceList.kt +28 -28
- package/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/DeviceScanner.kt +189 -189
- package/dist/esm/bleClient.js.map +1 -1
- package/dist/esm/conversion.js.map +1 -1
- package/dist/esm/queue.js.map +1 -1
- package/dist/esm/validators.js.map +1 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +41 -41
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +41 -41
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/BluetoothLe/Conversion.swift +83 -83
- package/ios/Sources/BluetoothLe/Device.swift +422 -423
- package/ios/Sources/BluetoothLe/DeviceListView.swift +121 -121
- package/ios/Sources/BluetoothLe/DeviceManager.swift +409 -503
- package/ios/Sources/BluetoothLe/Logging.swift +8 -8
- package/ios/Sources/BluetoothLe/Plugin.swift +768 -775
- package/ios/Sources/BluetoothLe/ScanFilters.swift +114 -0
- package/ios/Sources/BluetoothLe/ThreadSafeDictionary.swift +61 -15
- package/ios/Tests/BluetoothLeTests/ConversionTests.swift +55 -55
- package/ios/Tests/BluetoothLeTests/PluginTests.swift +27 -27
- package/ios/Tests/BluetoothLeTests/ScanFiltersTests.swift +153 -0
- package/package.json +114 -115
|
@@ -1,423 +1,422 @@
|
|
|
1
|
-
// swiftlint:disable type_body_length
|
|
2
|
-
import Foundation
|
|
3
|
-
import CoreBluetooth
|
|
4
|
-
|
|
5
|
-
class Device: NSObject, CBPeripheralDelegate {
|
|
6
|
-
typealias Callback = (_ success: Bool, _ value: String) -> Void
|
|
7
|
-
|
|
8
|
-
private var peripheral: CBPeripheral!
|
|
9
|
-
private
|
|
10
|
-
private
|
|
11
|
-
private var servicesCount = 0
|
|
12
|
-
private var servicesDiscovered = 0
|
|
13
|
-
private var characteristicsCount = 0
|
|
14
|
-
private var characteristicsDiscovered = 0
|
|
15
|
-
|
|
16
|
-
init(
|
|
17
|
-
_ peripheral: CBPeripheral
|
|
18
|
-
) {
|
|
19
|
-
super.init()
|
|
20
|
-
self.peripheral = peripheral
|
|
21
|
-
self.peripheral.delegate = self
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
func getName() -> String? {
|
|
25
|
-
return self.peripheral.name
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
func getId() -> String {
|
|
29
|
-
return self.peripheral.identifier.uuidString
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
func isConnected() -> Bool {
|
|
33
|
-
return self.peripheral.state == CBPeripheralState.connected
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
func getPeripheral() -> CBPeripheral {
|
|
37
|
-
return self.peripheral
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
func
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
func
|
|
50
|
-
_
|
|
51
|
-
|
|
52
|
-
) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.peripheral.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
let
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
let
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
self.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
_
|
|
414
|
-
_
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
1
|
+
// swiftlint:disable type_body_length
|
|
2
|
+
import Foundation
|
|
3
|
+
import CoreBluetooth
|
|
4
|
+
|
|
5
|
+
class Device: NSObject, CBPeripheralDelegate {
|
|
6
|
+
typealias Callback = (_ success: Bool, _ value: String) -> Void
|
|
7
|
+
|
|
8
|
+
private var peripheral: CBPeripheral!
|
|
9
|
+
private let callbackMap = ThreadSafeDictionary<String, Callback>()
|
|
10
|
+
private let timeoutMap = ThreadSafeDictionary<String, DispatchWorkItem>()
|
|
11
|
+
private var servicesCount = 0
|
|
12
|
+
private var servicesDiscovered = 0
|
|
13
|
+
private var characteristicsCount = 0
|
|
14
|
+
private var characteristicsDiscovered = 0
|
|
15
|
+
|
|
16
|
+
init(
|
|
17
|
+
_ peripheral: CBPeripheral
|
|
18
|
+
) {
|
|
19
|
+
super.init()
|
|
20
|
+
self.peripheral = peripheral
|
|
21
|
+
self.peripheral.delegate = self
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
func getName() -> String? {
|
|
25
|
+
return self.peripheral.name
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func getId() -> String {
|
|
29
|
+
return self.peripheral.identifier.uuidString
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func isConnected() -> Bool {
|
|
33
|
+
return self.peripheral.state == CBPeripheralState.connected
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func getPeripheral() -> CBPeripheral {
|
|
37
|
+
return self.peripheral
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func updatePeripheral(_ newPeripheral: CBPeripheral) {
|
|
41
|
+
guard newPeripheral.identifier == self.peripheral.identifier else {
|
|
42
|
+
log("Warning: Attempted to update peripheral with different UUID")
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
self.peripheral = newPeripheral
|
|
46
|
+
self.peripheral.delegate = self
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func setOnConnected(
|
|
50
|
+
_ connectionTimeout: Double,
|
|
51
|
+
_ callback: @escaping Callback
|
|
52
|
+
) {
|
|
53
|
+
let key = "connect"
|
|
54
|
+
self.callbackMap[key] = callback
|
|
55
|
+
self.setTimeout(key, "Connection timeout", connectionTimeout)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func peripheral(
|
|
59
|
+
_ peripheral: CBPeripheral,
|
|
60
|
+
didDiscoverServices error: Error?
|
|
61
|
+
) {
|
|
62
|
+
log("didDiscoverServices")
|
|
63
|
+
if let error = error {
|
|
64
|
+
log("Error", error.localizedDescription)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
self.servicesCount = peripheral.services?.count ?? 0
|
|
68
|
+
self.servicesDiscovered = 0
|
|
69
|
+
self.characteristicsCount = 0
|
|
70
|
+
self.characteristicsDiscovered = 0
|
|
71
|
+
for service in peripheral.services ?? [] {
|
|
72
|
+
peripheral.discoverCharacteristics(nil, for: service)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func peripheral(
|
|
77
|
+
_ peripheral: CBPeripheral,
|
|
78
|
+
didDiscoverCharacteristicsFor service: CBService,
|
|
79
|
+
error: Error?
|
|
80
|
+
) {
|
|
81
|
+
self.servicesDiscovered += 1
|
|
82
|
+
log("didDiscoverCharacteristicsFor", self.servicesDiscovered, self.servicesCount)
|
|
83
|
+
self.characteristicsCount += service.characteristics?.count ?? 0
|
|
84
|
+
for characteristic in service.characteristics ?? [] {
|
|
85
|
+
peripheral.discoverDescriptors(for: characteristic)
|
|
86
|
+
}
|
|
87
|
+
// if the last service does not have characteristics, resolve the connect call now
|
|
88
|
+
if self.servicesDiscovered >= self.servicesCount && self.characteristicsDiscovered >= self.characteristicsCount {
|
|
89
|
+
self.resolve("connect", "Connection successful.")
|
|
90
|
+
self.resolve("discoverServices", "Services discovered.")
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func peripheral(
|
|
95
|
+
_ peripheral: CBPeripheral,
|
|
96
|
+
didDiscoverDescriptorsFor characteristic: CBCharacteristic,
|
|
97
|
+
error: Error?
|
|
98
|
+
) {
|
|
99
|
+
self.characteristicsDiscovered += 1
|
|
100
|
+
if self.servicesDiscovered >= self.servicesCount && self.characteristicsDiscovered >= self.characteristicsCount {
|
|
101
|
+
self.resolve("connect", "Connection successful.")
|
|
102
|
+
self.resolve("discoverServices", "Services discovered.")
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func getServices() -> [CBService] {
|
|
107
|
+
return self.peripheral.services ?? []
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func discoverServices(
|
|
111
|
+
_ timeout: Double,
|
|
112
|
+
_ callback: @escaping Callback
|
|
113
|
+
) {
|
|
114
|
+
let key = "discoverServices"
|
|
115
|
+
self.callbackMap[key] = callback
|
|
116
|
+
self.peripheral.discoverServices(nil)
|
|
117
|
+
self.setTimeout(key, "Service discovery timeout.", timeout)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
func getMtu() -> Int {
|
|
121
|
+
// maximumWriteValueLength is 3 bytes less than ATT MTU
|
|
122
|
+
return self.peripheral.maximumWriteValueLength(for: .withoutResponse) + 3
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
func readRssi(
|
|
126
|
+
_ timeout: Double,
|
|
127
|
+
_ callback: @escaping Callback
|
|
128
|
+
) {
|
|
129
|
+
let key = "readRssi"
|
|
130
|
+
self.callbackMap[key] = callback
|
|
131
|
+
log("Reading RSSI value")
|
|
132
|
+
self.peripheral.readRSSI()
|
|
133
|
+
self.setTimeout(key, "Reading RSSI timeout.", timeout)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func peripheral(
|
|
137
|
+
_ peripheral: CBPeripheral,
|
|
138
|
+
didReadRSSI RSSI: NSNumber,
|
|
139
|
+
error: Error?
|
|
140
|
+
) {
|
|
141
|
+
let key = "readRssi"
|
|
142
|
+
if let error = error {
|
|
143
|
+
self.reject(key, error.localizedDescription)
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
self.resolve(key, RSSI.stringValue)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private func getCharacteristic(
|
|
150
|
+
_ serviceUUID: CBUUID,
|
|
151
|
+
_ characteristicUUID: CBUUID
|
|
152
|
+
) -> CBCharacteristic? {
|
|
153
|
+
for service in peripheral.services ?? [] {
|
|
154
|
+
if service.uuid == serviceUUID {
|
|
155
|
+
for characteristic in service.characteristics ?? [] {
|
|
156
|
+
if characteristic.uuid == characteristicUUID {
|
|
157
|
+
return characteristic
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return nil
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private func getDescriptor(
|
|
166
|
+
_ serviceUUID: CBUUID,
|
|
167
|
+
_ characteristicUUID: CBUUID,
|
|
168
|
+
_ descriptorUUID: CBUUID
|
|
169
|
+
) -> CBDescriptor? {
|
|
170
|
+
guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
|
|
171
|
+
return nil
|
|
172
|
+
}
|
|
173
|
+
for descriptor in characteristic.descriptors ?? [] {
|
|
174
|
+
if descriptor.uuid == descriptorUUID {
|
|
175
|
+
return descriptor
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return nil
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
func read(
|
|
182
|
+
_ serviceUUID: CBUUID,
|
|
183
|
+
_ characteristicUUID: CBUUID,
|
|
184
|
+
_ timeout: Double,
|
|
185
|
+
_ callback: @escaping Callback
|
|
186
|
+
) {
|
|
187
|
+
let key = "read|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
|
|
188
|
+
self.callbackMap[key] = callback
|
|
189
|
+
guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
|
|
190
|
+
self.reject(key, "Characteristic not found.")
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
log("Reading value")
|
|
194
|
+
self.peripheral.readValue(for: characteristic)
|
|
195
|
+
self.setTimeout(key, "Read timeout.", timeout)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
func peripheral(
|
|
199
|
+
_ peripheral: CBPeripheral,
|
|
200
|
+
didUpdateValueFor characteristic: CBCharacteristic,
|
|
201
|
+
error: Error?
|
|
202
|
+
) {
|
|
203
|
+
let key = self.getKey("read", characteristic)
|
|
204
|
+
let notifyKey = self.getKey("notification", characteristic)
|
|
205
|
+
if let error = error {
|
|
206
|
+
self.reject(key, error.localizedDescription)
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
if characteristic.value == nil {
|
|
210
|
+
self.reject(key, "Characteristic contains no value.")
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
// reading
|
|
214
|
+
let valueString = dataToString(characteristic.value!)
|
|
215
|
+
self.resolve(key, valueString)
|
|
216
|
+
|
|
217
|
+
// notifications
|
|
218
|
+
if let callback = self.callbackMap[notifyKey] {
|
|
219
|
+
callback(true, valueString)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
func readDescriptor(
|
|
224
|
+
_ serviceUUID: CBUUID,
|
|
225
|
+
_ characteristicUUID: CBUUID,
|
|
226
|
+
_ descriptorUUID: CBUUID,
|
|
227
|
+
_ timeout: Double,
|
|
228
|
+
_ callback: @escaping Callback
|
|
229
|
+
) {
|
|
230
|
+
let key = "readDescriptor|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)|\(descriptorUUID.uuidString)"
|
|
231
|
+
self.callbackMap[key] = callback
|
|
232
|
+
guard let descriptor = self.getDescriptor(serviceUUID, characteristicUUID, descriptorUUID) else {
|
|
233
|
+
self.reject(key, "Descriptor not found.")
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
log("Reading descriptor value")
|
|
237
|
+
self.peripheral.readValue(for: descriptor)
|
|
238
|
+
self.setTimeout(key, "Read descriptor timeout.", timeout)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
func peripheral(
|
|
242
|
+
_ peripheral: CBPeripheral,
|
|
243
|
+
didUpdateValueFor descriptor: CBDescriptor,
|
|
244
|
+
error: Error?
|
|
245
|
+
) {
|
|
246
|
+
let key = self.getKey("readDescriptor", descriptor)
|
|
247
|
+
if let error = error {
|
|
248
|
+
self.reject(key, error.localizedDescription)
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
if descriptor.value == nil {
|
|
252
|
+
self.reject(key, "Descriptor contains no value.")
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
let valueString = descriptorValueToString(descriptor.value!)
|
|
256
|
+
self.resolve(key, valueString)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
func write(
|
|
260
|
+
_ serviceUUID: CBUUID,
|
|
261
|
+
_ characteristicUUID: CBUUID,
|
|
262
|
+
_ value: String,
|
|
263
|
+
_ writeType: CBCharacteristicWriteType,
|
|
264
|
+
_ timeout: Double,
|
|
265
|
+
_ callback: @escaping Callback
|
|
266
|
+
) {
|
|
267
|
+
let key = "write|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
|
|
268
|
+
self.callbackMap[key] = callback
|
|
269
|
+
guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
|
|
270
|
+
self.reject(key, "Characteristic not found.")
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
let data: Data = stringToData(value)
|
|
274
|
+
self.peripheral.writeValue(data, for: characteristic, type: writeType)
|
|
275
|
+
if writeType == CBCharacteristicWriteType.withResponse {
|
|
276
|
+
self.setTimeout(key, "Write timeout.", timeout)
|
|
277
|
+
} else {
|
|
278
|
+
self.resolve(key, "Successfully written value.")
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
func peripheral(
|
|
283
|
+
_ peripheral: CBPeripheral,
|
|
284
|
+
didWriteValueFor characteristic: CBCharacteristic,
|
|
285
|
+
error: Error?
|
|
286
|
+
) {
|
|
287
|
+
let key = self.getKey("write", characteristic)
|
|
288
|
+
if let error = error {
|
|
289
|
+
self.reject(key, error.localizedDescription)
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
self.resolve(key, "Successfully written value.")
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
func writeDescriptor(
|
|
296
|
+
_ serviceUUID: CBUUID,
|
|
297
|
+
_ characteristicUUID: CBUUID,
|
|
298
|
+
_ descriptorUUID: CBUUID,
|
|
299
|
+
_ value: String,
|
|
300
|
+
_ timeout: Double,
|
|
301
|
+
_ callback: @escaping Callback
|
|
302
|
+
) {
|
|
303
|
+
let key = "writeDescriptor|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)|\(descriptorUUID.uuidString)"
|
|
304
|
+
self.callbackMap[key] = callback
|
|
305
|
+
guard let descriptor = self.getDescriptor(serviceUUID, characteristicUUID, descriptorUUID) else {
|
|
306
|
+
self.reject(key, "Descriptor not found.")
|
|
307
|
+
return
|
|
308
|
+
}
|
|
309
|
+
let data: Data = stringToData(value)
|
|
310
|
+
self.peripheral.writeValue(data, for: descriptor)
|
|
311
|
+
self.setTimeout(key, "Write descriptor timeout.", timeout)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
func peripheral(
|
|
315
|
+
_ peripheral: CBPeripheral,
|
|
316
|
+
didWriteValueFor descriptor: CBDescriptor,
|
|
317
|
+
error: Error?
|
|
318
|
+
) {
|
|
319
|
+
let key = self.getKey("writeDescriptor", descriptor)
|
|
320
|
+
if let error = error {
|
|
321
|
+
self.reject(key, error.localizedDescription)
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
self.resolve(key, "Successfully written descriptor value.")
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
func setNotifications(
|
|
328
|
+
_ serviceUUID: CBUUID,
|
|
329
|
+
_ characteristicUUID: CBUUID,
|
|
330
|
+
_ enable: Bool,
|
|
331
|
+
_ notifyCallback: Callback?,
|
|
332
|
+
_ timeout: Double,
|
|
333
|
+
_ callback: @escaping Callback
|
|
334
|
+
) {
|
|
335
|
+
let key = "setNotifications|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
|
|
336
|
+
let notifyKey = "notification|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
|
|
337
|
+
self.callbackMap[key] = callback
|
|
338
|
+
if let notifyCallback = notifyCallback {
|
|
339
|
+
self.callbackMap[notifyKey] = notifyCallback
|
|
340
|
+
}
|
|
341
|
+
guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
|
|
342
|
+
self.reject(key, "Characteristic not found.")
|
|
343
|
+
return
|
|
344
|
+
}
|
|
345
|
+
log("Set notifications", enable)
|
|
346
|
+
self.peripheral.setNotifyValue(enable, for: characteristic)
|
|
347
|
+
self.setTimeout(key, "Set notifications timeout.", timeout)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
func peripheral(
|
|
351
|
+
_ peripheral: CBPeripheral,
|
|
352
|
+
didUpdateNotificationStateFor characteristic: CBCharacteristic,
|
|
353
|
+
error: Error?
|
|
354
|
+
) {
|
|
355
|
+
let key = self.getKey("setNotifications", characteristic)
|
|
356
|
+
if let error = error {
|
|
357
|
+
self.reject(key, error.localizedDescription)
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
self.resolve(key, "Successfully set notifications.")
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
private func getKey(
|
|
364
|
+
_ prefix: String,
|
|
365
|
+
_ characteristic: CBCharacteristic?
|
|
366
|
+
) -> String {
|
|
367
|
+
let serviceUUIDString: String
|
|
368
|
+
if let service = characteristic?.service {
|
|
369
|
+
serviceUUIDString = cbuuidToStringUppercase(service.uuid)
|
|
370
|
+
} else {
|
|
371
|
+
serviceUUIDString = "UNKNOWN-SERVICE"
|
|
372
|
+
}
|
|
373
|
+
let characteristicUUIDString: String
|
|
374
|
+
if let characteristic = characteristic {
|
|
375
|
+
characteristicUUIDString = cbuuidToStringUppercase(characteristic.uuid)
|
|
376
|
+
} else {
|
|
377
|
+
characteristicUUIDString = "UNKNOWN-CHARACTERISTIC"
|
|
378
|
+
}
|
|
379
|
+
return "\(prefix)|\(serviceUUIDString)|\(characteristicUUIDString)"
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private func getKey(
|
|
383
|
+
_ prefix: String,
|
|
384
|
+
_ descriptor: CBDescriptor
|
|
385
|
+
) -> String {
|
|
386
|
+
let baseKey = self.getKey(prefix, descriptor.characteristic)
|
|
387
|
+
let descriptorUUIDString = cbuuidToStringUppercase(descriptor.uuid)
|
|
388
|
+
return "\(baseKey)|\(descriptorUUIDString)"
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
private func resolve(
|
|
392
|
+
_ key: String,
|
|
393
|
+
_ value: String
|
|
394
|
+
) {
|
|
395
|
+
guard let callback = self.callbackMap.removeValue(forKey: key) else { return }
|
|
396
|
+
self.timeoutMap.removeValue(forKey: key)?.cancel()
|
|
397
|
+
log("Resolve", key, value)
|
|
398
|
+
callback(true, value)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private func reject(
|
|
402
|
+
_ key: String,
|
|
403
|
+
_ value: String
|
|
404
|
+
) {
|
|
405
|
+
guard let callback = self.callbackMap.removeValue(forKey: key) else { return }
|
|
406
|
+
self.timeoutMap.removeValue(forKey: key)?.cancel()
|
|
407
|
+
log("Reject", key, value)
|
|
408
|
+
callback(false, value)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private func setTimeout(
|
|
412
|
+
_ key: String,
|
|
413
|
+
_ message: String,
|
|
414
|
+
_ timeout: Double
|
|
415
|
+
) {
|
|
416
|
+
let workItem = DispatchWorkItem {
|
|
417
|
+
self.reject(key, message)
|
|
418
|
+
}
|
|
419
|
+
self.timeoutMap[key] = workItem
|
|
420
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + timeout, execute: workItem)
|
|
421
|
+
}
|
|
422
|
+
}
|