munim-bluetooth 0.3.2 → 0.3.4

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.
@@ -14,14 +14,14 @@ class HybridMunimBluetooth: HybridMunimBluetoothSpec {
14
14
  // Peripheral Manager
15
15
  private var peripheralManager: CBPeripheralManager?
16
16
  private var peripheralServices: [CBMutableService] = []
17
- private var currentAdvertisingData: [String: Any] = [:]
17
+ private var currentAdvertisingData: AdvertisingDataTypes?
18
18
 
19
19
  // Central Manager
20
20
  private var centralManager: CBCentralManager?
21
21
  private var discoveredPeripherals: [String: CBPeripheral] = [:]
22
22
  private var connectedPeripherals: [String: CBPeripheral] = [:]
23
23
  private var peripheralCharacteristics: [String: [CBCharacteristic]] = [:]
24
- private var scanOptions: [String: Any]?
24
+ private var scanOptions: ScanOptions?
25
25
  private var isScanning = false
26
26
 
27
27
  // Event emitter
@@ -36,7 +36,7 @@ class HybridMunimBluetooth: HybridMunimBluetoothSpec {
36
36
 
37
37
  // MARK: - Peripheral Features
38
38
 
39
- func startAdvertising(options: [String: Any]) throws {
39
+ override func startAdvertising(options: AdvertisingOptions) throws {
40
40
  guard let peripheralManager = peripheralManager,
41
41
  peripheralManager.state == .poweredOn else {
42
42
  throw NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Bluetooth is not powered on"])
@@ -44,31 +44,33 @@ class HybridMunimBluetooth: HybridMunimBluetoothSpec {
44
44
 
45
45
  var advertisingData: [String: Any] = [:]
46
46
 
47
- // Process comprehensive advertising data
48
- if let advertisingDataDict = options["advertisingData"] as? [String: Any] {
49
- processAdvertisingData(advertisingDataDict, into: &advertisingData)
47
+ // Service UUIDs
48
+ if !options.serviceUUIDs.isEmpty {
49
+ let uuids = options.serviceUUIDs.compactMap { CBUUID(string: $0) }
50
+ advertisingData[CBAdvertisementDataServiceUUIDsKey] = uuids
50
51
  }
51
52
 
52
- // Legacy support
53
- if let localName = options["localName"] as? String {
53
+ // Local name
54
+ if let localName = options.localName {
54
55
  advertisingData[CBAdvertisementDataLocalNameKey] = localName
55
56
  }
56
57
 
57
- if let serviceUUIDs = options["serviceUUIDs"] as? [String], !serviceUUIDs.isEmpty {
58
- let uuids = serviceUUIDs.compactMap { CBUUID(string: $0) }
59
- advertisingData[CBAdvertisementDataServiceUUIDsKey] = uuids
60
- }
61
-
62
- if let manufacturerData = options["manufacturerData"] as? String,
58
+ // Manufacturer data
59
+ if let manufacturerData = options.manufacturerData,
63
60
  let data = hexStringToData(manufacturerData) {
64
61
  advertisingData[CBAdvertisementDataManufacturerDataKey] = data
65
62
  }
66
63
 
67
- currentAdvertisingData = advertisingData
64
+ // Advertising data
65
+ if let advertisingDataTypes = options.advertisingData {
66
+ processAdvertisingData(advertisingDataTypes, into: &advertisingData)
67
+ }
68
+
69
+ currentAdvertisingData = options.advertisingData
68
70
  peripheralManager.startAdvertising(advertisingData as? [String: Any])
69
71
  }
70
72
 
71
- func updateAdvertisingData(advertisingData: [String: Any]) throws {
73
+ override func updateAdvertisingData(advertisingData: AdvertisingDataTypes) throws {
72
74
  guard let peripheralManager = peripheralManager,
73
75
  peripheralManager.state == .poweredOn else {
74
76
  throw NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Bluetooth is not powered on"])
@@ -79,360 +81,231 @@ class HybridMunimBluetooth: HybridMunimBluetoothSpec {
79
81
  var newAdvertisingData: [String: Any] = [:]
80
82
  processAdvertisingData(advertisingData, into: &newAdvertisingData)
81
83
 
82
- currentAdvertisingData = newAdvertisingData
84
+ currentAdvertisingData = advertisingData
83
85
  peripheralManager.startAdvertising(newAdvertisingData as? [String: Any])
84
86
  }
85
87
 
86
- func getAdvertisingData() throws -> [String: Any] {
87
- return currentAdvertisingData
88
+ override func getAdvertisingData() throws -> Promise<AdvertisingDataTypes> {
89
+ return Promise { resolver in
90
+ resolver.resolve(self.currentAdvertisingData ?? AdvertisingDataTypes())
91
+ }
88
92
  }
89
93
 
90
- func stopAdvertising() throws {
94
+ override func stopAdvertising() throws {
91
95
  peripheralManager?.stopAdvertising()
92
- currentAdvertisingData = [:]
96
+ currentAdvertisingData = nil
93
97
  }
94
98
 
95
- func setServices(services: [[String: Any]]) throws {
99
+ override func setServices(services: [GATTService]) throws {
96
100
  peripheralServices.removeAll()
97
101
 
98
- for serviceDict in services {
99
- guard let uuidString = serviceDict["uuid"] as? String else { continue }
100
-
101
- let serviceUUID = CBUUID(string: uuidString)
102
- let service = CBMutableService(type: serviceUUID, primary: true)
102
+ for service in services {
103
+ let serviceUUID = CBUUID(string: service.uuid)
104
+ let mutableService = CBMutableService(type: serviceUUID, primary: true)
103
105
 
104
106
  var characteristics: [CBMutableCharacteristic] = []
105
107
 
106
- if let characteristicsArray = serviceDict["characteristics"] as? [[String: Any]] {
107
- for charDict in characteristicsArray {
108
- guard let charUUIDString = charDict["uuid"] as? String else { continue }
109
-
110
- let charUUID = CBUUID(string: charUUIDString)
111
- var properties: CBCharacteristicProperties = []
112
-
113
- if let propertiesArray = charDict["properties"] as? [String] {
114
- for prop in propertiesArray {
115
- switch prop {
116
- case "read":
117
- properties.insert(.read)
118
- case "write":
119
- properties.insert(.write)
120
- case "notify":
121
- properties.insert(.notify)
122
- case "indicate":
123
- properties.insert(.indicate)
124
- default:
125
- break
126
- }
127
- }
108
+ for characteristic in service.characteristics {
109
+ let charUUID = CBUUID(string: characteristic.uuid)
110
+
111
+ var properties: CBCharacteristicProperties = []
112
+ for prop in characteristic.properties {
113
+ switch prop {
114
+ case "read":
115
+ properties.insert(.read)
116
+ case "write":
117
+ properties.insert(.write)
118
+ case "writeWithoutResponse":
119
+ properties.insert(.writeWithoutResponse)
120
+ case "notify":
121
+ properties.insert(.notify)
122
+ case "indicate":
123
+ properties.insert(.indicate)
124
+ default:
125
+ break
128
126
  }
129
-
130
- var value: Data?
131
- if let valueString = charDict["value"] as? String {
132
- value = valueString.data(using: .utf8)
127
+ }
128
+
129
+ var value: Data?
130
+ if let valueString = characteristic.value {
131
+ value = hexStringToData(valueString)
132
+ if !properties.contains(.read) {
133
133
  properties.insert(.read)
134
134
  }
135
-
136
- let permissions: CBAttributePermissions = value != nil ? .readable : [.readable, .writeable]
137
-
138
- let characteristic = CBMutableCharacteristic(
139
- type: charUUID,
140
- properties: properties,
141
- value: value,
142
- permissions: permissions
143
- )
144
-
145
- characteristics.append(characteristic)
146
135
  }
136
+
137
+ let permissions: CBAttributePermissions = value != nil ? .readable : [.readable, .writeable]
138
+
139
+ let mutableChar = CBMutableCharacteristic(
140
+ type: charUUID,
141
+ properties: properties,
142
+ value: value,
143
+ permissions: permissions
144
+ )
145
+
146
+ characteristics.append(mutableChar)
147
147
  }
148
148
 
149
- service.characteristics = characteristics
150
- peripheralServices.append(service)
149
+ mutableService.characteristics = characteristics
150
+ peripheralServices.append(mutableService)
151
151
  }
152
152
 
153
- peripheralManager?.removeAllServices()
154
153
  for service in peripheralServices {
155
154
  peripheralManager?.add(service)
156
155
  }
157
156
  }
158
157
 
159
- // MARK: - Central Features
158
+ // MARK: - Central/Manager Features
160
159
 
161
- func isBluetoothEnabled() throws -> Bool {
162
- guard let centralManager = centralManager else { return false }
163
- return centralManager.state == .poweredOn
160
+ override func isBluetoothEnabled() throws -> Promise<Bool> {
161
+ return Promise { resolver in
162
+ let isEnabled = self.centralManager?.state == .poweredOn
163
+ resolver.resolve(isEnabled ?? false)
164
+ }
164
165
  }
165
166
 
166
- func requestBluetoothPermission() throws -> Bool {
167
- guard let centralManager = centralManager else { return false }
168
- // On iOS, permission is requested automatically when creating CBCentralManager
169
- // The state will be .unauthorized if permission is denied
170
- return centralManager.state != .unauthorized
167
+ override func requestBluetoothPermission() throws -> Promise<Bool> {
168
+ return Promise { resolver in
169
+ // In iOS, permissions are handled by CBPeripheralManager/CBCentralManager
170
+ resolver.resolve(true)
171
+ }
171
172
  }
172
173
 
173
- func startScan(options: [String: Any]?) throws {
174
+ override func startScan(options: ScanOptions?) throws {
174
175
  guard let centralManager = centralManager,
175
176
  centralManager.state == .poweredOn else {
176
177
  throw NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Bluetooth is not powered on"])
177
178
  }
178
179
 
179
- guard !isScanning else { return }
180
-
181
180
  scanOptions = options
182
181
  isScanning = true
183
- discoveredPeripherals.removeAll()
184
182
 
185
- var serviceUUIDs: [CBUUID]?
186
- if let serviceUUIDsArray = options?["serviceUUIDs"] as? [String] {
187
- serviceUUIDs = serviceUUIDsArray.compactMap { CBUUID(string: $0) }
183
+ var scanOptions: [String: Any] = [:]
184
+ if let options = options {
185
+ scanOptions[CBCentralManagerScanOptionAllowDuplicatesKey] = options.allowDuplicates ?? false
188
186
  }
189
187
 
190
- centralManager.scanForPeripherals(withServices: serviceUUIDs, options: [
191
- CBCentralManagerScanOptionAllowDuplicatesKey: options?["allowDuplicates"] as? Bool ?? false
192
- ])
188
+ centralManager.scanForPeripherals(withServices: nil, options: scanOptions as [String : Any])
193
189
  }
194
190
 
195
- func stopScan() throws {
196
- guard isScanning else { return }
191
+ override func stopScan() throws {
197
192
  centralManager?.stopScan()
198
193
  isScanning = false
199
- scanOptions = nil
200
194
  }
201
195
 
202
- func connect(deviceId: String) throws {
203
- guard let peripheral = discoveredPeripherals[deviceId] else {
204
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not found"])
196
+ override func connect(deviceId: String) throws -> Promise<Void> {
197
+ return Promise { resolver in
198
+ guard let peripheral = self.discoveredPeripherals[deviceId] else {
199
+ resolver.reject(NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Device not found"]))
200
+ return
201
+ }
202
+
203
+ self.centralManager?.connect(peripheral, options: nil)
204
+ self.connectedPeripherals[deviceId] = peripheral
205
+ resolver.resolve(())
205
206
  }
206
-
207
- centralManager?.connect(peripheral, options: nil)
208
207
  }
209
208
 
210
- func disconnect(deviceId: String) throws {
211
- guard let peripheral = connectedPeripherals[deviceId] ?? discoveredPeripherals[deviceId] else {
212
- return
213
- }
214
-
209
+ override func disconnect(deviceId: String) throws {
210
+ guard let peripheral = connectedPeripherals[deviceId] else { return }
215
211
  centralManager?.cancelPeripheralConnection(peripheral)
212
+ connectedPeripherals.removeValue(forKey: deviceId)
216
213
  }
217
214
 
218
- func discoverServices(deviceId: String) throws -> [[String: Any]] {
219
- guard let peripheral = connectedPeripherals[deviceId] else {
220
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not connected"])
215
+ override func discoverServices(deviceId: String) throws -> Promise<[GATTService]> {
216
+ return Promise { resolver in
217
+ guard let peripheral = self.connectedPeripherals[deviceId] else {
218
+ resolver.reject(NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Device not connected"]))
219
+ return
220
+ }
221
+
222
+ peripheral.discoverServices(nil)
223
+ resolver.resolve([])
221
224
  }
222
-
223
- peripheral.discoverServices(nil)
224
-
225
- // Wait for services to be discovered (in real implementation, this would be async)
226
- // For now, return empty array - services will be discovered via delegate callbacks
227
- return []
228
225
  }
229
226
 
230
- func readCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws -> [String: Any] {
231
- guard let peripheral = connectedPeripherals[deviceId] else {
232
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not connected"])
233
- }
234
-
235
- guard let characteristics = peripheralCharacteristics[deviceId],
236
- let characteristic = characteristics.first(where: {
237
- $0.service?.uuid == CBUUID(string: serviceUUID) &&
238
- $0.uuid == CBUUID(string: characteristicUUID)
239
- }) else {
240
- throw NSError(domain: "MunimBluetooth", code: 3, userInfo: [NSLocalizedDescriptionKey: "Characteristic not found"])
227
+ override func readCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws -> Promise<CharacteristicValue> {
228
+ return Promise { resolver in
229
+ resolver.reject(NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Not implemented"]))
241
230
  }
242
-
243
- peripheral.readValue(for: characteristic)
244
-
245
- // Return empty for now - value will come via delegate callback
246
- return [
247
- "value": "",
248
- "serviceUUID": serviceUUID,
249
- "characteristicUUID": characteristicUUID
250
- ]
251
231
  }
252
232
 
253
- func writeCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String, value: String, writeType: String?) throws {
254
- guard let peripheral = connectedPeripherals[deviceId] else {
255
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not connected"])
256
- }
257
-
258
- guard let characteristics = peripheralCharacteristics[deviceId],
259
- let characteristic = characteristics.first(where: {
260
- $0.service?.uuid == CBUUID(string: serviceUUID) &&
261
- $0.uuid == CBUUID(string: characteristicUUID)
262
- }) else {
263
- throw NSError(domain: "MunimBluetooth", code: 3, userInfo: [NSLocalizedDescriptionKey: "Characteristic not found"])
264
- }
265
-
266
- guard let data = hexStringToData(value) else {
267
- throw NSError(domain: "MunimBluetooth", code: 4, userInfo: [NSLocalizedDescriptionKey: "Invalid hex string"])
233
+ override func writeCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String, value: String, writeType: WriteType?) throws -> Promise<Void> {
234
+ return Promise { resolver in
235
+ resolver.reject(NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Not implemented"]))
268
236
  }
269
-
270
- let type: CBCharacteristicWriteType = (writeType == "writeWithoutResponse") ? .withoutResponse : .withResponse
271
- peripheral.writeValue(data, for: characteristic, type: type)
272
237
  }
273
238
 
274
- func subscribeToCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws {
275
- guard let peripheral = connectedPeripherals[deviceId] else {
276
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not connected"])
277
- }
278
-
279
- guard let characteristics = peripheralCharacteristics[deviceId],
280
- let characteristic = characteristics.first(where: {
281
- $0.service?.uuid == CBUUID(string: serviceUUID) &&
282
- $0.uuid == CBUUID(string: characteristicUUID)
283
- }) else {
284
- throw NSError(domain: "MunimBluetooth", code: 3, userInfo: [NSLocalizedDescriptionKey: "Characteristic not found"])
285
- }
286
-
287
- peripheral.setNotifyValue(true, for: characteristic)
239
+ override func subscribeToCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws {
240
+ // Not implemented
288
241
  }
289
242
 
290
- func unsubscribeFromCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws {
291
- guard let peripheral = connectedPeripherals[deviceId] else {
292
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not connected"])
293
- }
294
-
295
- guard let characteristics = peripheralCharacteristics[deviceId],
296
- let characteristic = characteristics.first(where: {
297
- $0.service?.uuid == CBUUID(string: serviceUUID) &&
298
- $0.uuid == CBUUID(string: characteristicUUID)
299
- }) else {
300
- throw NSError(domain: "MunimBluetooth", code: 3, userInfo: [NSLocalizedDescriptionKey: "Characteristic not found"])
301
- }
302
-
303
- peripheral.setNotifyValue(false, for: characteristic)
243
+ override func unsubscribeFromCharacteristic(deviceId: String, serviceUUID: String, characteristicUUID: String) throws {
244
+ // Not implemented
304
245
  }
305
246
 
306
- func getConnectedDevices() throws -> [String] {
307
- return Array(connectedPeripherals.keys)
247
+ override func getConnectedDevices() throws -> Promise<[String]> {
248
+ return Promise { resolver in
249
+ resolver.resolve(Array(self.connectedPeripherals.keys))
250
+ }
308
251
  }
309
252
 
310
- func readRSSI(deviceId: String) throws -> Double {
311
- guard let peripheral = connectedPeripherals[deviceId] else {
312
- throw NSError(domain: "MunimBluetooth", code: 2, userInfo: [NSLocalizedDescriptionKey: "Device not connected"])
253
+ override func readRSSI(deviceId: String) throws -> Promise<Double> {
254
+ return Promise { resolver in
255
+ guard let peripheral = self.connectedPeripherals[deviceId] else {
256
+ resolver.reject(NSError(domain: "MunimBluetooth", code: 1, userInfo: [NSLocalizedDescriptionKey: "Device not connected"]))
257
+ return
258
+ }
259
+
260
+ peripheral.readRSSI()
261
+ resolver.resolve(0)
313
262
  }
314
-
315
- peripheral.readRSSI()
316
- // RSSI will come via delegate callback
317
- return 0.0
318
263
  }
319
264
 
320
- // MARK: - Event Management
321
-
322
- func addListener(eventName: String) throws {
323
- // Event listeners are handled by the event emitter
324
- // This is a no-op as Nitro modules handle events differently
265
+ override func addListener(eventName: String) throws {
266
+ // Event management
325
267
  }
326
268
 
327
- func removeListeners(count: Double) throws {
328
- // Event listeners are handled by the event emitter
329
- // This is a no-op as Nitro modules handle events differently
269
+ override func removeListeners(count: Double) throws {
270
+ // Event management
330
271
  }
331
272
 
332
273
  // MARK: - Helper Methods
333
274
 
334
- private func processAdvertisingData(_ dataDict: [String: Any], into advertisingData: inout [String: Any]) {
335
- // Flags
336
- if let flags = dataDict["flags"] as? Int {
337
- let isConnectable = (flags & 0x02) != 0
338
- advertisingData[CBAdvertisementDataIsConnectable] = isConnectable
339
- }
340
-
341
- // Service UUIDs
342
- addServiceUUIDs(dataDict["incompleteServiceUUIDs16"], to: &advertisingData, key: CBAdvertisementDataServiceUUIDsKey)
343
- addServiceUUIDs(dataDict["completeServiceUUIDs16"], to: &advertisingData, key: CBAdvertisementDataServiceUUIDsKey)
344
- addServiceUUIDs(dataDict["incompleteServiceUUIDs32"], to: &advertisingData, key: CBAdvertisementDataServiceUUIDsKey)
345
- addServiceUUIDs(dataDict["completeServiceUUIDs32"], to: &advertisingData, key: CBAdvertisementDataServiceUUIDsKey)
346
- addServiceUUIDs(dataDict["incompleteServiceUUIDs128"], to: &advertisingData, key: CBAdvertisementDataServiceUUIDsKey)
347
- addServiceUUIDs(dataDict["completeServiceUUIDs128"], to: &advertisingData, key: CBAdvertisementDataServiceUUIDsKey)
348
-
349
- // Local Name
350
- if let shortenedName = dataDict["shortenedLocalName"] as? String {
351
- advertisingData[CBAdvertisementDataLocalNameKey] = shortenedName
352
- }
353
- if let completeName = dataDict["completeLocalName"] as? String {
354
- advertisingData[CBAdvertisementDataLocalNameKey] = completeName
355
- }
275
+ private func hexStringToData(_ hex: String) -> Data? {
276
+ var data = Data()
277
+ var hex = hex
356
278
 
357
- // Tx Power Level
358
- if let txPower = dataDict["txPowerLevel"] as? Int {
359
- advertisingData[CBAdvertisementDataTxPowerLevelKey] = txPower
279
+ if hex.count % 2 != 0 {
280
+ hex = "0" + hex
360
281
  }
361
282
 
362
- // Service Solicitation
363
- addServiceUUIDs(dataDict["serviceSolicitationUUIDs16"], to: &advertisingData, key: CBAdvertisementDataSolicitedServiceUUIDsKey)
364
- addServiceUUIDs(dataDict["serviceSolicitationUUIDs128"], to: &advertisingData, key: CBAdvertisementDataSolicitedServiceUUIDsKey)
365
- addServiceUUIDs(dataDict["serviceSolicitationUUIDs32"], to: &advertisingData, key: CBAdvertisementDataSolicitedServiceUUIDsKey)
366
-
367
- // Service Data
368
- addServiceData(dataDict["serviceData16"], to: &advertisingData)
369
- addServiceData(dataDict["serviceData32"], to: &advertisingData)
370
- addServiceData(dataDict["serviceData128"], to: &advertisingData)
371
-
372
- // Appearance
373
- if let appearance = dataDict["appearance"] as? Int {
374
- let appearanceData = Data(bytes: [UInt8(appearance & 0xFF), UInt8((appearance >> 8) & 0xFF)], count: 2)
375
- advertisingData[CBUUID(string: "1800")] = appearanceData
283
+ let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
284
+ regex.enumerateMatches(in: hex, range: NSRange(hex.startIndex..., in: hex)) { match, _, _ in
285
+ let byteStr = (hex as NSString).substring(with: match!.range)
286
+ let num = UInt8(byteStr, radix: 16)!
287
+ data.append(num)
376
288
  }
377
289
 
378
- // Manufacturer Data
379
- if let manufacturerData = dataDict["manufacturerData"] as? String,
380
- let data = hexStringToData(manufacturerData) {
381
- advertisingData[CBAdvertisementDataManufacturerDataKey] = data
382
- }
290
+ return data.isEmpty ? nil : data
383
291
  }
384
292
 
385
- private func addServiceUUIDs(_ uuids: Any?, to advertisingData: inout [String: Any], key: String) {
386
- guard let uuidArray = uuids as? [String] else { return }
387
-
388
- let cbUUIDs = uuidArray.compactMap { CBUUID(string: $0) }
389
- if !cbUUIDs.isEmpty {
390
- if var existing = advertisingData[key] as? [CBUUID] {
391
- existing.append(contentsOf: cbUUIDs)
392
- advertisingData[key] = existing
393
- } else {
394
- advertisingData[key] = cbUUIDs
395
- }
293
+ private func processAdvertisingData(_ data: AdvertisingDataTypes, into advertisingData: inout [String: Any]) {
294
+ if let flags = data.flags {
295
+ advertisingData[CBAdvertisementDataIsConnectable] = true
396
296
  }
397
- }
398
-
399
- private func addServiceData(_ serviceDataArray: Any?, to advertisingData: inout [String: Any]) {
400
- guard let array = serviceDataArray as? [[String: Any]] else { return }
401
297
 
402
- for serviceData in array {
403
- guard let uuid = serviceData["uuid"] as? String,
404
- let dataString = serviceData["data"] as? String,
405
- let data = hexStringToData(dataString) else { continue }
406
-
407
- advertisingData[uuid] = data
298
+ if let completeLocalName = data.completeLocalName {
299
+ advertisingData[CBAdvertisementDataLocalNameKey] = completeLocalName
408
300
  }
409
- }
410
-
411
- private func hexStringToData(_ hexString: String) -> Data? {
412
- let cleanHex = hexString.replacingOccurrences(of: " ", with: "")
413
- guard cleanHex.count % 2 == 0 else { return nil }
414
301
 
415
- var data = Data()
416
- var index = cleanHex.startIndex
417
-
418
- while index < cleanHex.endIndex {
419
- let nextIndex = cleanHex.index(index, offsetBy: 2)
420
- guard nextIndex <= cleanHex.endIndex else { break }
421
-
422
- let byteString = String(cleanHex[index..<nextIndex])
423
- if let byte = UInt8(byteString, radix: 16) {
424
- data.append(byte)
425
- }
426
-
427
- index = nextIndex
302
+ if let txPowerLevel = data.txPowerLevel {
303
+ advertisingData[CBAdvertisementDataTxPowerLevelKey] = txPowerLevel
428
304
  }
429
-
430
- return data
431
305
  }
432
306
  }
433
307
 
434
308
  // MARK: - CBPeripheralManagerDelegate
435
-
436
309
  extension HybridMunimBluetooth: CBPeripheralManagerDelegate {
437
310
  func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
438
311
  // Handle state updates
@@ -440,34 +313,36 @@ extension HybridMunimBluetooth: CBPeripheralManagerDelegate {
440
313
 
441
314
  func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
442
315
  if let error = error {
443
- // Emit error event
316
+ eventEmitter?.emit("advertisingError", ["error": error.localizedDescription])
317
+ } else {
318
+ eventEmitter?.emit("advertisingStarted", [:])
444
319
  }
445
320
  }
446
321
 
447
322
  func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
448
323
  if let error = error {
449
- // Emit error event
324
+ eventEmitter?.emit("serviceError", ["error": error.localizedDescription])
325
+ } else {
326
+ eventEmitter?.emit("serviceAdded", ["uuid": service.uuid.uuidString])
450
327
  }
451
328
  }
452
329
  }
453
330
 
454
331
  // MARK: - CBCentralManagerDelegate
455
-
456
332
  extension HybridMunimBluetooth: CBCentralManagerDelegate {
457
333
  func centralManagerDidUpdateState(_ central: CBCentralManager) {
458
- // Handle state updates
334
+ let state = central.state
335
+ eventEmitter?.emit("bluetoothStateChanged", ["state": state.rawValue])
459
336
  }
460
337
 
461
338
  func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
462
339
  let deviceId = peripheral.identifier.uuidString
463
340
  discoveredPeripherals[deviceId] = peripheral
464
341
 
465
- // Emit deviceFound event
466
342
  eventEmitter?.emit("deviceFound", [
467
343
  "id": deviceId,
468
344
  "name": peripheral.name ?? "",
469
- "rssi": RSSI.intValue,
470
- "advertisingData": advertisementData
345
+ "rssi": RSSI.intValue
471
346
  ])
472
347
  }
473
348
 
@@ -476,7 +351,6 @@ extension HybridMunimBluetooth: CBCentralManagerDelegate {
476
351
  connectedPeripherals[deviceId] = peripheral
477
352
  peripheral.delegate = self
478
353
 
479
- // Emit deviceConnected event
480
354
  eventEmitter?.emit("deviceConnected", ["id": deviceId])
481
355
  }
482
356
 
@@ -485,14 +359,11 @@ extension HybridMunimBluetooth: CBCentralManagerDelegate {
485
359
  connectedPeripherals.removeValue(forKey: deviceId)
486
360
  peripheralCharacteristics.removeValue(forKey: deviceId)
487
361
 
488
- // Emit deviceDisconnected event
489
362
  eventEmitter?.emit("deviceDisconnected", ["id": deviceId])
490
363
  }
491
364
 
492
365
  func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
493
366
  let deviceId = peripheral.identifier.uuidString
494
-
495
- // Emit connectionFailed event
496
367
  eventEmitter?.emit("connectionFailed", [
497
368
  "id": deviceId,
498
369
  "error": error?.localizedDescription ?? "Unknown error"
@@ -501,24 +372,17 @@ extension HybridMunimBluetooth: CBCentralManagerDelegate {
501
372
  }
502
373
 
503
374
  // MARK: - CBPeripheralDelegate
504
-
505
375
  extension HybridMunimBluetooth: CBPeripheralDelegate {
506
376
  func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
507
377
  let deviceId = peripheral.identifier.uuidString
508
378
 
509
379
  guard let services = peripheral.services else { return }
510
380
 
511
- var servicesArray: [[String: Any]] = []
512
381
  for service in services {
513
382
  peripheral.discoverCharacteristics(nil, for: service)
514
- servicesArray.append(["uuid": service.uuid.uuidString])
515
383
  }
516
384
 
517
- // Emit servicesDiscovered event
518
- eventEmitter?.emit("servicesDiscovered", [
519
- "id": deviceId,
520
- "services": servicesArray
521
- ])
385
+ eventEmitter?.emit("servicesDiscovered", ["id": deviceId])
522
386
  }
523
387
 
524
388
  func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
@@ -531,26 +395,7 @@ extension HybridMunimBluetooth: CBPeripheralDelegate {
531
395
  }
532
396
  peripheralCharacteristics[deviceId]?.append(contentsOf: characteristics)
533
397
 
534
- // Emit characteristicsDiscovered event
535
- var characteristicsArray: [[String: Any]] = []
536
- for characteristic in characteristics {
537
- var properties: [String] = []
538
- if characteristic.properties.contains(.read) { properties.append("read") }
539
- if characteristic.properties.contains(.write) { properties.append("write") }
540
- if characteristic.properties.contains(.notify) { properties.append("notify") }
541
- if characteristic.properties.contains(.indicate) { properties.append("indicate") }
542
-
543
- characteristicsArray.append([
544
- "uuid": characteristic.uuid.uuidString,
545
- "properties": properties
546
- ])
547
- }
548
-
549
- eventEmitter?.emit("characteristicsDiscovered", [
550
- "id": deviceId,
551
- "serviceUUID": service.uuid.uuidString,
552
- "characteristics": characteristicsArray
553
- ])
398
+ eventEmitter?.emit("characteristicsDiscovered", ["id": deviceId])
554
399
  }
555
400
 
556
401
  func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
@@ -560,7 +405,6 @@ extension HybridMunimBluetooth: CBPeripheralDelegate {
560
405
 
561
406
  let hexString = data.map { String(format: "%02x", $0) }.joined()
562
407
 
563
- // Emit characteristicValueChanged event
564
408
  eventEmitter?.emit("characteristicValueChanged", [
565
409
  "id": deviceId,
566
410
  "serviceUUID": characteristic.service?.uuid.uuidString ?? "",
@@ -575,29 +419,10 @@ extension HybridMunimBluetooth: CBPeripheralDelegate {
575
419
  if let error = error {
576
420
  eventEmitter?.emit("writeError", [
577
421
  "id": deviceId,
578
- "serviceUUID": characteristic.service?.uuid.uuidString ?? "",
579
- "characteristicUUID": characteristic.uuid.uuidString,
580
422
  "error": error.localizedDescription
581
423
  ])
582
424
  } else {
583
- eventEmitter?.emit("writeSuccess", [
584
- "id": deviceId,
585
- "serviceUUID": characteristic.service?.uuid.uuidString ?? "",
586
- "characteristicUUID": characteristic.uuid.uuidString
587
- ])
588
- }
589
- }
590
-
591
- func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
592
- let deviceId = peripheral.identifier.uuidString
593
-
594
- if let error = error {
595
- eventEmitter?.emit("subscriptionError", [
596
- "id": deviceId,
597
- "serviceUUID": characteristic.service?.uuid.uuidString ?? "",
598
- "characteristicUUID": characteristic.uuid.uuidString,
599
- "error": error.localizedDescription
600
- ])
425
+ eventEmitter?.emit("writeSuccess", ["id": deviceId])
601
426
  }
602
427
  }
603
428
 
@@ -605,21 +430,14 @@ extension HybridMunimBluetooth: CBPeripheralDelegate {
605
430
  let deviceId = peripheral.identifier.uuidString
606
431
 
607
432
  if let error = error {
608
- eventEmitter?.emit("rssiError", [
609
- "id": deviceId,
610
- "error": error.localizedDescription
611
- ])
433
+ eventEmitter?.emit("rssiError", ["error": error.localizedDescription])
612
434
  } else {
613
- eventEmitter?.emit("rssiUpdated", [
614
- "id": deviceId,
615
- "rssi": RSSI.intValue
616
- ])
435
+ eventEmitter?.emit("rssiUpdated", ["id": deviceId, "rssi": RSSI.intValue])
617
436
  }
618
437
  }
619
438
  }
620
439
 
621
- // MARK: - Event Emitter Helper
622
-
440
+ // MARK: - Helper Classes
623
441
  class NitroEventEmitter {
624
442
  private let moduleName: String
625
443
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "munim-bluetooth",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "A comprehensive React Native library for all your Bluetooth Low Energy (BLE) needs, supporting both peripheral and central roles with Expo support",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",