react-native-ble-nitro 1.0.0-beta.15 → 1.0.0-beta.17
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/ios/BleNitroBleManager.swift +68 -494
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
///
|
|
2
2
|
/// BleNitroBleManager.swift
|
|
3
|
-
/// React Native BLE Nitro - iOS Implementation
|
|
3
|
+
/// React Native BLE Nitro - iOS Implementation (Minimal Stub)
|
|
4
4
|
/// Copyright © 2025 Zyke (https://zyke.co)
|
|
5
5
|
///
|
|
6
6
|
|
|
@@ -9,571 +9,145 @@ import CoreBluetooth
|
|
|
9
9
|
import NitroModules
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Minimal BLE Manager implementation stub for iOS
|
|
13
|
+
* TODO: Implement full CoreBluetooth integration
|
|
14
14
|
*/
|
|
15
|
-
public class BleNitroBleManager:
|
|
16
|
-
|
|
17
|
-
// MARK: - Properties
|
|
18
|
-
private var centralManager: CBCentralManager!
|
|
19
|
-
private var logLevel: BleLogLevel = .none
|
|
20
|
-
private var isScanning = false
|
|
21
|
-
private var scanListener: ((_ error: NativeBleError?, _ scannedDevice: NativeDevice?) -> Void)?
|
|
22
|
-
private var stateChangeListener: ((_ newState: State) -> Void)?
|
|
23
|
-
private var connectedDevices: [String: CBPeripheral] = [:]
|
|
24
|
-
private var discoveredDevices: [String: CBPeripheral] = [:]
|
|
25
|
-
private var deviceDisconnectListeners: [String: ((_ error: NativeBleError?, _ device: NativeDevice?) -> Void)] = [:]
|
|
26
|
-
private var characteristicMonitors: [String: ((_ error: NativeBleError?, _ characteristic: NativeCharacteristic?) -> Void)] = [:]
|
|
27
|
-
private var pendingOperations: [String: Any] = [:]
|
|
28
|
-
|
|
29
|
-
// State restoration
|
|
30
|
-
private var restoreIdentifier: String?
|
|
31
|
-
private var isInitialized = false
|
|
32
|
-
private var restoredState: BleRestoredState?
|
|
33
|
-
|
|
34
|
-
// MARK: - Initialization
|
|
35
|
-
public override init() {
|
|
36
|
-
super.init()
|
|
37
|
-
// Initialize with default options - will be reconfigured in initialize() method
|
|
38
|
-
self.centralManager = CBCentralManager(delegate: self, queue: nil)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private func reinitializeCentralManager() {
|
|
42
|
-
// Create CBCentralManager with state restoration if identifier is provided
|
|
43
|
-
var options: [String: Any] = [:]
|
|
44
|
-
if let restoreId = restoreIdentifier {
|
|
45
|
-
options[CBCentralManagerOptionRestoreIdentifierKey] = restoreId
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
self.centralManager = CBCentralManager(delegate: self, queue: nil, options: options.isEmpty ? nil : options)
|
|
49
|
-
}
|
|
15
|
+
public class BleNitroBleManager: HybridBleManagerSpec {
|
|
50
16
|
|
|
51
17
|
public var memorySize: Int {
|
|
52
18
|
return MemorySize.MemorySize_estimate(self)
|
|
53
19
|
}
|
|
54
20
|
|
|
55
|
-
// MARK: - HybridBleManagerSpec Implementation
|
|
21
|
+
// MARK: - HybridBleManagerSpec Implementation (Stubs)
|
|
56
22
|
|
|
57
23
|
public func destroy() throws -> Promise<Void> {
|
|
58
|
-
return Promise.
|
|
59
|
-
self.stopDeviceScan()
|
|
60
|
-
self.centralManager.delegate = nil
|
|
61
|
-
self.connectedDevices.removeAll()
|
|
62
|
-
self.discoveredDevices.removeAll()
|
|
63
|
-
self.deviceDisconnectListeners.removeAll()
|
|
64
|
-
self.characteristicMonitors.removeAll()
|
|
65
|
-
self.pendingOperations.removeAll()
|
|
66
|
-
resolve(())
|
|
67
|
-
}
|
|
24
|
+
return Promise.resolve(withResult: ())
|
|
68
25
|
}
|
|
69
26
|
|
|
70
27
|
public func initialize(options: BleManagerNitroOptions) throws -> Promise<Void> {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Store the restore identifier
|
|
74
|
-
self.restoreIdentifier = restoreId
|
|
75
|
-
|
|
76
|
-
// Reinitialize the central manager with state restoration
|
|
77
|
-
self.reinitializeCentralManager()
|
|
78
|
-
|
|
79
|
-
print("BleNitro: Initialized with restore state identifier: \(restoreId)")
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
self.isInitialized = true
|
|
83
|
-
print("BleNitro: BLE Manager initialized")
|
|
84
|
-
})
|
|
28
|
+
print("BleNitro: iOS implementation not yet complete")
|
|
29
|
+
return Promise.resolve(withResult: ())
|
|
85
30
|
}
|
|
86
31
|
|
|
87
32
|
public func getRestoredState() throws -> Promise<BleRestoredState?> {
|
|
88
|
-
return Promise.resolve(
|
|
89
|
-
return self.restoredState
|
|
90
|
-
})
|
|
33
|
+
return Promise.resolve(withResult: nil)
|
|
91
34
|
}
|
|
92
35
|
|
|
93
36
|
public func setLogLevel(logLevel: BleLogLevel) throws -> Promise<BleLogLevel> {
|
|
94
|
-
return Promise.resolve(
|
|
95
|
-
self.logLevel = logLevel
|
|
96
|
-
return logLevel
|
|
97
|
-
})
|
|
37
|
+
return Promise.resolve(withResult: logLevel)
|
|
98
38
|
}
|
|
99
39
|
|
|
100
40
|
public func logLevel() throws -> Promise<BleLogLevel> {
|
|
101
|
-
return Promise.resolve(
|
|
41
|
+
return Promise.resolve(withResult: .none)
|
|
102
42
|
}
|
|
103
43
|
|
|
104
44
|
public func cancelTransaction(transactionId: String) throws -> Promise<Void> {
|
|
105
|
-
return Promise.
|
|
106
|
-
self.pendingOperations.removeValue(forKey: transactionId)
|
|
107
|
-
resolve(())
|
|
108
|
-
}
|
|
45
|
+
return Promise.resolve(withResult: ())
|
|
109
46
|
}
|
|
110
47
|
|
|
111
48
|
public func enable(transactionId: String?) throws -> Promise<Void> {
|
|
112
|
-
return Promise.
|
|
113
|
-
// CoreBluetooth manages Bluetooth state automatically
|
|
114
|
-
// We can't programmatically enable Bluetooth on iOS
|
|
115
|
-
if self.centralManager.state == .poweredOn {
|
|
116
|
-
resolve(())
|
|
117
|
-
} else {
|
|
118
|
-
let error = self.createBleError(.BluetoothPoweredOff, message: "Bluetooth is not powered on")
|
|
119
|
-
reject(error)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
49
|
+
return Promise.reject(error: BleError.notImplemented("enable not implemented on iOS yet"))
|
|
122
50
|
}
|
|
123
51
|
|
|
124
52
|
public func disable(transactionId: String?) throws -> Promise<Void> {
|
|
125
|
-
return Promise.
|
|
126
|
-
// CoreBluetooth doesn't allow programmatic disabling on iOS
|
|
127
|
-
let error = self.createBleError(.BluetoothUnsupported, message: "Cannot programmatically disable Bluetooth on iOS")
|
|
128
|
-
reject(error)
|
|
129
|
-
}
|
|
53
|
+
return Promise.reject(error: BleError.notImplemented("disable not implemented on iOS yet"))
|
|
130
54
|
}
|
|
131
55
|
|
|
132
56
|
public func state() throws -> Promise<State> {
|
|
133
|
-
return Promise.resolve(
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
public func onStateChange(listener: @escaping (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return Subscription(remove: {
|
|
144
|
-
self.stateChangeListener = nil
|
|
145
|
-
})
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
public func startDeviceScan(uuids: [String]?, options: ScanOptions?, listener: @escaping (_ error: NativeBleError?, _ scannedDevice: NativeDevice?) -> Void) throws -> Promise<Void> {
|
|
149
|
-
return Promise.async { resolve, reject in
|
|
150
|
-
guard self.centralManager.state == .poweredOn else {
|
|
151
|
-
let error = self.createBleError(.BluetoothPoweredOff, message: "Bluetooth is not powered on")
|
|
152
|
-
reject(error)
|
|
153
|
-
return
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
self.scanListener = listener
|
|
157
|
-
self.isScanning = true
|
|
158
|
-
|
|
159
|
-
var serviceUUIDs: [CBUUID]? = nil
|
|
160
|
-
if let uuids = uuids {
|
|
161
|
-
serviceUUIDs = uuids.compactMap { CBUUID(string: $0) }
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
var scanOptions: [String: Any] = [:]
|
|
165
|
-
if let options = options {
|
|
166
|
-
if options.allowDuplicates == true {
|
|
167
|
-
scanOptions[CBCentralManagerScanOptionAllowDuplicatesKey] = true
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
self.centralManager.scanForPeripherals(withServices: serviceUUIDs, options: scanOptions)
|
|
172
|
-
resolve(())
|
|
173
|
-
}
|
|
57
|
+
return Promise.resolve(withResult: .unknown)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public func onStateChange(listener: @escaping (State) -> Void, emitCurrentState: Bool?) throws -> Subscription {
|
|
61
|
+
return Subscription(remove: {})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public func startDeviceScan(uuids: [String]?, options: ScanOptions?, listener: @escaping (NativeBleError?, NativeDevice?) -> Void) throws -> Promise<Void> {
|
|
65
|
+
return Promise.reject(error: BleError.notImplemented("startDeviceScan not implemented on iOS yet"))
|
|
174
66
|
}
|
|
175
67
|
|
|
176
68
|
public func stopDeviceScan() throws -> Promise<Void> {
|
|
177
|
-
return Promise.resolve(
|
|
178
|
-
if self.isScanning {
|
|
179
|
-
self.centralManager.stopScan()
|
|
180
|
-
self.isScanning = false
|
|
181
|
-
self.scanListener = nil
|
|
182
|
-
}
|
|
183
|
-
})
|
|
69
|
+
return Promise.resolve(withResult: ())
|
|
184
70
|
}
|
|
185
71
|
|
|
186
72
|
public func requestConnectionPriorityForDevice(deviceIdentifier: String, connectionPriority: ConnectionPriority, transactionId: String?) throws -> Promise<NativeDevice> {
|
|
187
|
-
return Promise.
|
|
188
|
-
// iOS doesn't have direct connection priority control like Android
|
|
189
|
-
// Return the device as-is since this is mostly an Android feature
|
|
190
|
-
if let peripheral = self.connectedDevices[deviceIdentifier] {
|
|
191
|
-
let device = self.createNativeDevice(from: peripheral)
|
|
192
|
-
resolve(device)
|
|
193
|
-
} else {
|
|
194
|
-
let error = self.createBleError(.DeviceNotFound, message: "Device not found: \(deviceIdentifier)")
|
|
195
|
-
reject(error)
|
|
196
|
-
}
|
|
197
|
-
}
|
|
73
|
+
return Promise.reject(error: BleError.notImplemented("requestConnectionPriorityForDevice not implemented on iOS yet"))
|
|
198
74
|
}
|
|
199
75
|
|
|
200
76
|
public func readRSSIForDevice(deviceIdentifier: String, transactionId: String?) throws -> Promise<NativeDevice> {
|
|
201
|
-
return Promise.
|
|
202
|
-
guard let peripheral = self.connectedDevices[deviceIdentifier] else {
|
|
203
|
-
let error = self.createBleError(.DeviceNotFound, message: "Device not found: \(deviceIdentifier)")
|
|
204
|
-
reject(error)
|
|
205
|
-
return
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if let transactionId = transactionId {
|
|
209
|
-
self.pendingOperations[transactionId] = resolve
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
peripheral.readRSSI()
|
|
213
|
-
}
|
|
77
|
+
return Promise.reject(error: BleError.notImplemented("readRSSIForDevice not implemented on iOS yet"))
|
|
214
78
|
}
|
|
215
79
|
|
|
216
80
|
public func requestMTUForDevice(deviceIdentifier: String, mtu: Double, transactionId: String?) throws -> Promise<NativeDevice> {
|
|
217
|
-
return Promise.
|
|
218
|
-
// iOS automatically negotiates MTU, we can't explicitly set it
|
|
219
|
-
if let peripheral = self.connectedDevices[deviceIdentifier] {
|
|
220
|
-
let device = self.createNativeDevice(from: peripheral)
|
|
221
|
-
resolve(device)
|
|
222
|
-
} else {
|
|
223
|
-
let error = self.createBleError(.DeviceNotFound, message: "Device not found: \(deviceIdentifier)")
|
|
224
|
-
reject(error)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
81
|
+
return Promise.reject(error: BleError.notImplemented("requestMTUForDevice not implemented on iOS yet"))
|
|
227
82
|
}
|
|
228
83
|
|
|
229
84
|
public func devices(deviceIdentifiers: [String]) throws -> Promise<[NativeDevice]> {
|
|
230
|
-
return Promise.resolve(
|
|
231
|
-
return deviceIdentifiers.compactMap { identifier in
|
|
232
|
-
if let peripheral = self.discoveredDevices[identifier] ?? self.connectedDevices[identifier] {
|
|
233
|
-
return self.createNativeDevice(from: peripheral)
|
|
234
|
-
}
|
|
235
|
-
return nil
|
|
236
|
-
}
|
|
237
|
-
})
|
|
85
|
+
return Promise.resolve(withResult: [])
|
|
238
86
|
}
|
|
239
87
|
|
|
240
88
|
public func connectedDevices(serviceUUIDs: [String]) throws -> Promise<[NativeDevice]> {
|
|
241
|
-
return Promise.resolve(
|
|
242
|
-
let serviceUUIDs = serviceUUIDs.compactMap { CBUUID(string: $0) }
|
|
243
|
-
let peripherals = self.centralManager.retrieveConnectedPeripherals(withServices: serviceUUIDs)
|
|
244
|
-
return peripherals.map { self.createNativeDevice(from: $0) }
|
|
245
|
-
})
|
|
89
|
+
return Promise.resolve(withResult: [])
|
|
246
90
|
}
|
|
247
91
|
|
|
248
92
|
public func connectToDevice(deviceIdentifier: String, options: ConnectionOptions?) throws -> Promise<NativeDevice> {
|
|
249
|
-
return Promise.
|
|
250
|
-
guard let peripheral = self.discoveredDevices[deviceIdentifier] else {
|
|
251
|
-
let error = self.createBleError(.DeviceNotFound, message: "Device not found: \(deviceIdentifier)")
|
|
252
|
-
reject(error)
|
|
253
|
-
return
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
var connectOptions: [String: Any] = [:]
|
|
257
|
-
if let options = options {
|
|
258
|
-
connectOptions[CBConnectPeripheralOptionNotifyOnConnectionKey] = true
|
|
259
|
-
connectOptions[CBConnectPeripheralOptionNotifyOnDisconnectionKey] = true
|
|
260
|
-
connectOptions[CBConnectPeripheralOptionNotifyOnNotificationKey] = true
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
self.pendingOperations[deviceIdentifier] = resolve
|
|
264
|
-
self.centralManager.connect(peripheral, options: connectOptions)
|
|
265
|
-
}
|
|
93
|
+
return Promise.reject(error: BleError.notImplemented("connectToDevice not implemented on iOS yet"))
|
|
266
94
|
}
|
|
267
95
|
|
|
268
96
|
public func cancelDeviceConnection(deviceIdentifier: String) throws -> Promise<NativeDevice> {
|
|
269
|
-
return Promise.
|
|
270
|
-
guard let peripheral = self.connectedDevices[deviceIdentifier] else {
|
|
271
|
-
let error = self.createBleError(.DeviceNotFound, message: "Device not found: \(deviceIdentifier)")
|
|
272
|
-
reject(error)
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
self.pendingOperations[deviceIdentifier] = resolve
|
|
277
|
-
self.centralManager.cancelPeripheralConnection(peripheral)
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
public func onDeviceDisconnected(deviceIdentifier: String, listener: @escaping (_ error: NativeBleError?, _ device: NativeDevice?) -> Void) throws -> Subscription {
|
|
282
|
-
self.deviceDisconnectListeners[deviceIdentifier] = listener
|
|
283
|
-
|
|
284
|
-
return Subscription(remove: {
|
|
285
|
-
self.deviceDisconnectListeners.removeValue(forKey: deviceIdentifier)
|
|
286
|
-
})
|
|
97
|
+
return Promise.reject(error: BleError.notImplemented("cancelDeviceConnection not implemented on iOS yet"))
|
|
287
98
|
}
|
|
288
99
|
|
|
289
|
-
public func
|
|
290
|
-
return
|
|
291
|
-
return self.connectedDevices[deviceIdentifier] != nil
|
|
292
|
-
})
|
|
100
|
+
public func onDeviceDisconnected(deviceIdentifier: String, listener: @escaping (NativeBleError?, NativeDevice?) -> Void) throws -> Subscription {
|
|
101
|
+
return Subscription(remove: {})
|
|
293
102
|
}
|
|
294
103
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
104
|
+
public func isDeviceConnected(deviceIdentifier: String) throws -> Promise<Bool> {
|
|
105
|
+
return Promise.resolve(withResult: false)
|
|
106
|
+
}
|
|
298
107
|
|
|
299
108
|
public func discoverAllServicesAndCharacteristicsForDevice(deviceIdentifier: String, transactionId: String?) throws -> Promise<NativeDevice> {
|
|
300
|
-
return Promise.
|
|
301
|
-
guard let peripheral = self.connectedDevices[deviceIdentifier] else {
|
|
302
|
-
let error = self.createBleError(.DeviceNotFound, message: "Device not found: \(deviceIdentifier)")
|
|
303
|
-
reject(error)
|
|
304
|
-
return
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if let transactionId = transactionId {
|
|
308
|
-
self.pendingOperations[transactionId] = resolve
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
peripheral.discoverServices(nil)
|
|
312
|
-
}
|
|
109
|
+
return Promise.reject(error: BleError.notImplemented("discoverAllServicesAndCharacteristicsForDevice not implemented on iOS yet"))
|
|
313
110
|
}
|
|
314
111
|
|
|
315
112
|
public func servicesForDevice(deviceIdentifier: String) throws -> Promise<[NativeService]> {
|
|
316
|
-
return Promise.resolve(
|
|
317
|
-
guard let peripheral = self.connectedDevices[deviceIdentifier],
|
|
318
|
-
let services = peripheral.services else {
|
|
319
|
-
return []
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return services.enumerated().map { index, service in
|
|
323
|
-
return NativeService(
|
|
324
|
-
id: Double(index),
|
|
325
|
-
uuid: service.uuid.uuidString,
|
|
326
|
-
deviceID: deviceIdentifier,
|
|
327
|
-
isPrimary: service.isPrimary
|
|
328
|
-
)
|
|
329
|
-
}
|
|
330
|
-
})
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// MARK: - CBCentralManagerDelegate
|
|
334
|
-
|
|
335
|
-
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
336
|
-
let state = mapCBManagerState(central.state)
|
|
337
|
-
stateChangeListener?(state)
|
|
338
|
-
print("BleNitro: Central manager state changed to: \(central.state.rawValue)")
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
|
|
342
|
-
let deviceId = peripheral.identifier.uuidString
|
|
343
|
-
discoveredDevices[deviceId] = peripheral
|
|
344
|
-
|
|
345
|
-
let device = createNativeDevice(from: peripheral, advertisementData: advertisementData, rssi: RSSI)
|
|
346
|
-
scanListener?(nil, device)
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
|
350
|
-
let deviceId = peripheral.identifier.uuidString
|
|
351
|
-
connectedDevices[deviceId] = peripheral
|
|
352
|
-
peripheral.delegate = self
|
|
353
|
-
|
|
354
|
-
if let resolve = pendingOperations[deviceId] as? (NativeDevice) -> Void {
|
|
355
|
-
let device = createNativeDevice(from: peripheral)
|
|
356
|
-
resolve(device)
|
|
357
|
-
pendingOperations.removeValue(forKey: deviceId)
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
|
362
|
-
let deviceId = peripheral.identifier.uuidString
|
|
363
|
-
connectedDevices.removeValue(forKey: deviceId)
|
|
364
|
-
|
|
365
|
-
let device = createNativeDevice(from: peripheral)
|
|
366
|
-
let bleError = error != nil ? createBleError(.DeviceDisconnected, message: error!.localizedDescription) : nil
|
|
367
|
-
|
|
368
|
-
deviceDisconnectListeners[deviceId]?(bleError, device)
|
|
369
|
-
deviceDisconnectListeners.removeValue(forKey: deviceId)
|
|
370
|
-
|
|
371
|
-
if let resolve = pendingOperations[deviceId] as? (NativeDevice) -> Void {
|
|
372
|
-
resolve(device)
|
|
373
|
-
pendingOperations.removeValue(forKey: deviceId)
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
|
|
378
|
-
let deviceId = peripheral.identifier.uuidString
|
|
379
|
-
|
|
380
|
-
if let reject = pendingOperations[deviceId] as? (Error) -> Void {
|
|
381
|
-
let bleError = createBleError(.DeviceConnectionFailed, message: error?.localizedDescription ?? "Connection failed")
|
|
382
|
-
reject(bleError)
|
|
383
|
-
pendingOperations.removeValue(forKey: deviceId)
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// MARK: - Helper Methods
|
|
388
|
-
|
|
389
|
-
private func mapCBManagerState(_ state: CBManagerState) -> State {
|
|
390
|
-
switch state {
|
|
391
|
-
case .unknown:
|
|
392
|
-
return .Unknown
|
|
393
|
-
case .resetting:
|
|
394
|
-
return .Resetting
|
|
395
|
-
case .unsupported:
|
|
396
|
-
return .Unsupported
|
|
397
|
-
case .unauthorized:
|
|
398
|
-
return .Unauthorized
|
|
399
|
-
case .poweredOff:
|
|
400
|
-
return .PoweredOff
|
|
401
|
-
case .poweredOn:
|
|
402
|
-
return .PoweredOn
|
|
403
|
-
@unknown default:
|
|
404
|
-
return .Unknown
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
private func createNativeDevice(from peripheral: CBPeripheral, advertisementData: [String: Any]? = nil, rssi: NSNumber? = nil) -> NativeDevice {
|
|
409
|
-
var serviceData: [ServiceDataEntry] = []
|
|
410
|
-
var serviceUUIDs: [String] = []
|
|
411
|
-
var manufacturerData: String? = nil
|
|
412
|
-
var localName: String? = nil
|
|
413
|
-
var txPowerLevel: Double? = nil
|
|
414
|
-
var isConnectable: Bool? = nil
|
|
415
|
-
var solicitedServiceUUIDs: [String] = []
|
|
416
|
-
var overflowServiceUUIDs: [String] = []
|
|
417
|
-
|
|
418
|
-
if let adData = advertisementData {
|
|
419
|
-
// Parse advertisement data
|
|
420
|
-
if let services = adData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] {
|
|
421
|
-
serviceUUIDs = services.map { $0.uuidString }
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if let data = adData[CBAdvertisementDataManufacturerDataKey] as? Data {
|
|
425
|
-
manufacturerData = data.base64EncodedString()
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
localName = adData[CBAdvertisementDataLocalNameKey] as? String
|
|
429
|
-
txPowerLevel = adData[CBAdvertisementDataTxPowerLevelKey] as? Double
|
|
430
|
-
isConnectable = adData[CBAdvertisementDataIsConnectable] as? Bool
|
|
431
|
-
|
|
432
|
-
if let services = adData[CBAdvertisementDataSolicitedServiceUUIDsKey] as? [CBUUID] {
|
|
433
|
-
solicitedServiceUUIDs = services.map { $0.uuidString }
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if let services = adData[CBAdvertisementDataOverflowServiceUUIDsKey] as? [CBUUID] {
|
|
437
|
-
overflowServiceUUIDs = services.map { $0.uuidString }
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if let serviceDataDict = adData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] {
|
|
441
|
-
serviceData = serviceDataDict.map { uuid, data in
|
|
442
|
-
ServiceDataEntry(uuid: uuid.uuidString, data: data.base64EncodedString())
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return NativeDevice(
|
|
448
|
-
id: peripheral.identifier.uuidString,
|
|
449
|
-
deviceName: peripheral.name ?? localName,
|
|
450
|
-
rssi: rssi?.doubleValue,
|
|
451
|
-
mtu: 23.0, // Default MTU on iOS
|
|
452
|
-
manufacturerData: manufacturerData,
|
|
453
|
-
serviceData: serviceData,
|
|
454
|
-
serviceUUIDs: serviceUUIDs.isEmpty ? nil : serviceUUIDs,
|
|
455
|
-
localName: localName,
|
|
456
|
-
txPowerLevel: txPowerLevel,
|
|
457
|
-
solicitedServiceUUIDs: solicitedServiceUUIDs.isEmpty ? nil : solicitedServiceUUIDs,
|
|
458
|
-
isConnectable: isConnectable,
|
|
459
|
-
overflowServiceUUIDs: overflowServiceUUIDs.isEmpty ? nil : overflowServiceUUIDs,
|
|
460
|
-
rawScanRecord: "" // iOS doesn't provide raw scan record
|
|
461
|
-
)
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
private func createBleError(_ errorCode: BleErrorCode, message: String) -> NativeBleError {
|
|
465
|
-
return NativeBleError(
|
|
466
|
-
errorCode: errorCode,
|
|
467
|
-
attErrorCode: nil,
|
|
468
|
-
iosErrorCode: nil,
|
|
469
|
-
androidErrorCode: nil,
|
|
470
|
-
reason: message,
|
|
471
|
-
deviceID: nil,
|
|
472
|
-
serviceUUID: nil,
|
|
473
|
-
characteristicUUID: nil,
|
|
474
|
-
descriptorUUID: nil,
|
|
475
|
-
internalMessage: message
|
|
476
|
-
)
|
|
113
|
+
return Promise.resolve(withResult: [])
|
|
477
114
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
extension BleNitroBleManager: CBPeripheralDelegate {
|
|
483
|
-
|
|
484
|
-
public func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
|
|
485
|
-
let deviceId = peripheral.identifier.uuidString
|
|
486
|
-
|
|
487
|
-
for (transactionId, operation) in pendingOperations {
|
|
488
|
-
if let resolve = operation as? (NativeDevice) -> Void {
|
|
489
|
-
let device = createNativeDevice(from: peripheral, rssi: RSSI)
|
|
490
|
-
resolve(device)
|
|
491
|
-
pendingOperations.removeValue(forKey: transactionId)
|
|
492
|
-
break
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
|
|
498
|
-
if let error = error {
|
|
499
|
-
// Handle service discovery error
|
|
500
|
-
return
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Discover characteristics for all services
|
|
504
|
-
peripheral.services?.forEach { service in
|
|
505
|
-
peripheral.discoverCharacteristics(nil, for: service)
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
|
510
|
-
if let error = error {
|
|
511
|
-
// Handle characteristic discovery error
|
|
512
|
-
return
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Discover descriptors for all characteristics
|
|
516
|
-
service.characteristics?.forEach { characteristic in
|
|
517
|
-
peripheral.discoverDescriptors(for: characteristic)
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
public func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
|
|
522
|
-
// Complete service discovery
|
|
523
|
-
let deviceId = peripheral.identifier.uuidString
|
|
524
|
-
|
|
525
|
-
for (transactionId, operation) in pendingOperations {
|
|
526
|
-
if let resolve = operation as? (NativeDevice) -> Void {
|
|
527
|
-
let device = createNativeDevice(from: peripheral)
|
|
528
|
-
resolve(device)
|
|
529
|
-
pendingOperations.removeValue(forKey: transactionId)
|
|
530
|
-
break
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// MARK: - CBCentralManagerDelegate State Restoration
|
|
536
|
-
|
|
537
|
-
public func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
|
|
538
|
-
// Handle state restoration
|
|
539
|
-
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] {
|
|
540
|
-
print("BleNitro: Restoring \(peripherals.count) peripherals")
|
|
541
|
-
|
|
542
|
-
// Add restored peripherals to our connected devices
|
|
543
|
-
for peripheral in peripherals {
|
|
544
|
-
let deviceId = peripheral.identifier.uuidString
|
|
545
|
-
connectedDevices[deviceId] = peripheral
|
|
546
|
-
peripheral.delegate = self
|
|
547
|
-
|
|
548
|
-
print("BleNitro: Restored peripheral: \(deviceId)")
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// Store restored state for later retrieval
|
|
552
|
-
if !peripherals.isEmpty {
|
|
553
|
-
let restoredDevices = peripherals.map(createNativeDevice)
|
|
554
|
-
self.restoredState = BleRestoredState(connectedPeripherals: restoredDevices)
|
|
555
|
-
print("BleNitro: Stored restored state with \(restoredDevices.count) devices")
|
|
556
|
-
}
|
|
557
|
-
}
|
|
115
|
+
|
|
116
|
+
public func characteristicsForDevice(deviceIdentifier: String, serviceUUID: String) throws -> Promise<[NativeCharacteristic]> {
|
|
117
|
+
return Promise.resolve(withResult: [])
|
|
558
118
|
}
|
|
559
119
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
* Simple subscription implementation for cleanup
|
|
564
|
-
*/
|
|
565
|
-
private class SubscriptionImpl {
|
|
566
|
-
private let cleanup: () -> Void
|
|
120
|
+
public func readCharacteristicForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String, transactionId: String?) throws -> Promise<NativeCharacteristic> {
|
|
121
|
+
return Promise.reject(error: BleError.notImplemented("readCharacteristicForDevice not implemented on iOS yet"))
|
|
122
|
+
}
|
|
567
123
|
|
|
568
|
-
|
|
569
|
-
|
|
124
|
+
public func writeCharacteristicWithResponseForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String, base64Value: String, transactionId: String?) throws -> Promise<NativeCharacteristic> {
|
|
125
|
+
return Promise.reject(error: BleError.notImplemented("writeCharacteristicWithResponseForDevice not implemented on iOS yet"))
|
|
570
126
|
}
|
|
571
127
|
|
|
572
|
-
public func
|
|
573
|
-
|
|
128
|
+
public func writeCharacteristicWithoutResponseForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String, base64Value: String, transactionId: String?) throws -> Promise<NativeCharacteristic> {
|
|
129
|
+
return Promise.reject(error: BleError.notImplemented("writeCharacteristicWithoutResponseForDevice not implemented on iOS yet"))
|
|
574
130
|
}
|
|
575
131
|
|
|
576
|
-
public func
|
|
577
|
-
return Subscription(remove:
|
|
132
|
+
public func monitorCharacteristicForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String, listener: @escaping (NativeBleError?, NativeCharacteristic?) -> Void, transactionId: String?, subscriptionType: CharacteristicSubscriptionType?) throws -> Subscription {
|
|
133
|
+
return Subscription(remove: {})
|
|
578
134
|
}
|
|
135
|
+
|
|
136
|
+
public func descriptorsForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String) throws -> Promise<[NativeDescriptor]> {
|
|
137
|
+
return Promise.resolve(withResult: [])
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public func readDescriptorForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String, descriptorUUID: String, transactionId: String?) throws -> Promise<NativeDescriptor> {
|
|
141
|
+
return Promise.reject(error: BleError.notImplemented("readDescriptorForDevice not implemented on iOS yet"))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public func writeDescriptorForDevice(deviceIdentifier: String, serviceUUID: String, characteristicUUID: String, descriptorUUID: String, valueBase64: String, transactionId: String?) throws -> Promise<NativeDescriptor> {
|
|
145
|
+
return Promise.reject(error: BleError.notImplemented("writeDescriptorForDevice not implemented on iOS yet"))
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// MARK: - Error Helper
|
|
150
|
+
|
|
151
|
+
enum BleError: Error {
|
|
152
|
+
case notImplemented(String)
|
|
579
153
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-ble-nitro",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.17",
|
|
4
4
|
"description": "High-performance React Native BLE library built on Nitro Modules - drop-in replacement for react-native-ble-plx",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|