react-native-ble-nitro 1.0.0 → 1.2.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 (58) hide show
  1. package/README.md +25 -17
  2. package/ios/BleNitroBleManager.swift +126 -57
  3. package/ios/BlePeripheralDelegate.swift +36 -8
  4. package/lib/commonjs/index.d.ts +29 -20
  5. package/lib/commonjs/index.d.ts.map +1 -1
  6. package/lib/commonjs/index.js +113 -143
  7. package/lib/commonjs/index.js.map +1 -1
  8. package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +19 -14
  9. package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
  10. package/lib/commonjs/specs/NativeBleNitro.nitro.js.map +1 -1
  11. package/lib/index.d.ts +29 -20
  12. package/lib/index.js +112 -142
  13. package/lib/specs/NativeBleNitro.nitro.d.ts +19 -14
  14. package/nitrogen/generated/android/BleNitroOnLoad.cpp +6 -12
  15. package/nitrogen/generated/android/c++/JBLEDevice.hpp +3 -0
  16. package/nitrogen/generated/android/c++/JFunc_void_BLEDevice.hpp +3 -0
  17. package/nitrogen/generated/android/c++/JFunc_void_bool_std__shared_ptr_ArrayBuffer__std__string.hpp +78 -0
  18. package/nitrogen/generated/android/c++/JFunc_void_std__string_std__shared_ptr_ArrayBuffer_.hpp +78 -0
  19. package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +111 -65
  20. package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +13 -13
  21. package/nitrogen/generated/android/c++/JManufacturerData.hpp +3 -0
  22. package/nitrogen/generated/android/c++/JManufacturerDataEntry.hpp +7 -15
  23. package/nitrogen/generated/android/c++/JOperationResult.hpp +58 -0
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/{Func_void_bool_std__vector_double__std__string.kt → Func_void_bool_std__shared_ptr_ArrayBuffer__std__string.kt} +12 -12
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/{Func_void_std__string_std__vector_double_.kt → Func_void_std__string_std__shared_ptr_ArrayBuffer_.kt} +12 -12
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt +20 -65
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/ManufacturerDataEntry.kt +1 -1
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/OperationResult.kt +32 -0
  29. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.cpp +15 -39
  30. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.hpp +108 -113
  31. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Umbrella.hpp +6 -0
  32. package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +57 -28
  33. package/nitrogen/generated/ios/swift/{Func_void_bool_std__vector_double__std__string.swift → Func_void_bool_std__shared_ptr_ArrayBuffer__std__string.swift} +11 -11
  34. package/nitrogen/generated/ios/swift/{Func_void_std__string_std__vector_double_.swift → Func_void_std__string_std__shared_ptr_ArrayBuffer_.swift} +11 -11
  35. package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +13 -13
  36. package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +84 -136
  37. package/nitrogen/generated/ios/swift/ManufacturerDataEntry.swift +5 -17
  38. package/nitrogen/generated/ios/swift/OperationResult.swift +64 -0
  39. package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.cpp +1 -1
  40. package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +20 -14
  41. package/nitrogen/generated/shared/c++/ManufacturerDataEntry.hpp +8 -7
  42. package/nitrogen/generated/shared/c++/OperationResult.hpp +72 -0
  43. package/package.json +1 -1
  44. package/react-native.config.js +10 -2
  45. package/src/__tests__/index.test.ts +19 -22
  46. package/src/index.ts +147 -164
  47. package/src/specs/NativeBleNitro.nitro.ts +22 -14
  48. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +0 -74
  49. package/nitrogen/generated/android/c++/JFunc_void_bool_std__vector_double__std__string.hpp +0 -86
  50. package/nitrogen/generated/android/c++/JFunc_void_std__string_std__vector_double_.hpp +0 -86
  51. package/nitrogen/generated/android/c++/JFunc_void_std__vector_BLEDevice_.hpp +0 -99
  52. package/nitrogen/generated/android/c++/JFunc_void_std__vector_std__string_.hpp +0 -93
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_bool.kt +0 -81
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_std__vector_BLEDevice_.kt +0 -81
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_std__vector_std__string_.kt +0 -81
  56. package/nitrogen/generated/ios/swift/Func_void_bool.swift +0 -47
  57. package/nitrogen/generated/ios/swift/Func_void_std__vector_BLEDevice_.swift +0 -47
  58. package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +0 -47
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  A high-performance React Native BLE library built on [Nitro Modules](https://nitro.margelo.com/).
7
7
 
8
- Originally developed for [Zyke Band](https://zykeband.com) - a fitness and health tracker created by a small team.
8
+ Originally developed for [Zyke Band](https://zykeband.com?utm_source=github&utm_medium=readme&utm_campaign=opensource) - a fitness and health tracker created by a small team.
9
9
 
10
10
  ## ✨ Features
11
11
 
@@ -83,22 +83,22 @@ const ble = BleNitro.instance();
83
83
 
84
84
  ```typescript
85
85
  // Check if Bluetooth is enabled
86
- const isEnabled = await ble.isBluetoothEnabled();
86
+ const isEnabled = ble.isBluetoothEnabled();
87
87
 
88
88
  // Get current Bluetooth state
89
- const state = await ble.state();
89
+ const state = ble.state();
90
90
  // Returns: BLEState.PoweredOn, BLEState.PoweredOff, etc.
91
91
 
92
92
  // Request to enable Bluetooth (Android only)
93
93
  await ble.requestBluetoothEnable();
94
94
 
95
95
  // Subscribe to state changes
96
- const subscription = await ble.subscribeToStateChange((state) => {
96
+ const subscription = ble.subscribeToStateChange((state) => {
97
97
  console.log('Bluetooth state changed:', state);
98
98
  }, true); // true = emit initial state
99
99
 
100
100
  // Unsubscribe from state changes
101
- await subscription.remove();
101
+ subscription.remove();
102
102
 
103
103
  // Open Bluetooth settings
104
104
  await ble.openSettings();
@@ -108,7 +108,7 @@ await ble.openSettings();
108
108
 
109
109
  ```typescript
110
110
  // Start scanning for devices
111
- await ble.startScan({
111
+ ble.startScan({
112
112
  serviceUUIDs: ['180d'], // Optional: filter by service UUIDs
113
113
  rssiThreshold: -80, // Optional: minimum signal strength
114
114
  allowDuplicates: false // Optional: allow duplicate discoveries
@@ -117,13 +117,13 @@ await ble.startScan({
117
117
  });
118
118
 
119
119
  // Stop scanning
120
- await ble.stopScan();
120
+ ble.stopScan();
121
121
 
122
122
  // Check if currently scanning
123
- const isScanning = await ble.isScanning();
123
+ const isScanning = ble.isScanning();
124
124
 
125
125
  // Get already connected devices
126
- const connectedDevices = await ble.getConnectedDevices();
126
+ const connectedDevices = ble.getConnectedDevices(['180d']); // Optional: filter by service UUIDs
127
127
  ```
128
128
 
129
129
  #### 🔗 Device Connection
@@ -147,7 +147,11 @@ const deviceId = await ble.connect(deviceId);
147
147
  await ble.disconnect(deviceId);
148
148
 
149
149
  // Check connection status
150
- const isConnected = await ble.isConnected(deviceId);
150
+ const isConnected = ble.isConnected(deviceId);
151
+
152
+ // MTU negotiation (Android only, as iOS manages MTU automatically)
153
+ // iOS returns current MTU size
154
+ const mtu = await ble.requestMTU(deviceId, 256); // Request MTU size
151
155
  ```
152
156
 
153
157
  #### 🔧 Service Discovery
@@ -162,13 +166,13 @@ const services = await ble.getServices(deviceId);
162
166
  // Always returns full 128-bit UUIDs
163
167
 
164
168
  // Get characteristics for a service
165
- const characteristics = await ble.getCharacteristics(deviceId, serviceUUID);
169
+ const characteristics = ble.getCharacteristics(deviceId, serviceUUID);
166
170
  // Returns: ['00002a37-0000-1000-8000-00805f9b34fb', '00002a38-0000-1000-8000-00805f9b34fb', ...]
167
171
  // Always returns full 128-bit UUIDs
168
172
 
169
173
  // Note: You can use either short or long form UUIDs as input:
170
- const characteristics1 = await ble.getCharacteristics(deviceId, '180d'); // Short form
171
- const characteristics2 = await ble.getCharacteristics(deviceId, '0000180d-0000-1000-8000-00805f9b34fb'); // Long form
174
+ const characteristics1 = ble.getCharacteristics(deviceId, '180d'); // Short form
175
+ const characteristics2 = ble.getCharacteristics(deviceId, '0000180d-0000-1000-8000-00805f9b34fb'); // Long form
172
176
  // Both work identically - conversion handled automatically
173
177
  ```
174
178
 
@@ -211,7 +215,7 @@ await ble.writeCharacteristic(
211
215
 
212
216
  ```typescript
213
217
  // Subscribe to characteristic notifications
214
- const subscription = await ble.subscribeToCharacteristic(
218
+ const subscription = ble.subscribeToCharacteristic(
215
219
  deviceId,
216
220
  serviceUUID,
217
221
  characteristicUUID,
@@ -222,7 +226,7 @@ const subscription = await ble.subscribeToCharacteristic(
222
226
  );
223
227
 
224
228
  // Unsubscribe from notifications
225
- await subscription.remove();
229
+ subscription.remove();
226
230
 
227
231
  // Or unsubscribe directly
228
232
  await ble.unsubscribeFromCharacteristic(deviceId, serviceUUID, characteristicUUID);
@@ -240,7 +244,7 @@ const HEART_RATE_MEASUREMENT = '2a37';
240
244
  const deviceId = await ble.connect(heartRateDeviceId);
241
245
  await ble.discoverServices(deviceId);
242
246
 
243
- const subscription = await ble.subscribeToCharacteristic(
247
+ const subscription = ble.subscribeToCharacteristic(
244
248
  deviceId,
245
249
  HEART_RATE_SERVICE,
246
250
  HEART_RATE_MEASUREMENT,
@@ -249,6 +253,9 @@ const subscription = await ble.subscribeToCharacteristic(
249
253
  console.log('Heart rate:', heartRate, 'BPM');
250
254
  }
251
255
  );
256
+
257
+ // Unsubscribe when done
258
+ subscription.remove();
252
259
  ```
253
260
 
254
261
  #### Battery Level Reading
@@ -478,10 +485,11 @@ MIT License - see [LICENSE](./LICENSE) file.
478
485
 
479
486
  ## 🙏 Acknowledgments
480
487
 
481
- - [Zyke Band](https://zykeband.com) - The fitness tracker project that inspired this library
488
+ - [Zyke Band](https://zykeband.com?utm_source=github&utm_medium=readme&utm_campaign=opensource) - The fitness tracker project that inspired this library
482
489
  - [Marc Rousavy](https://github.com/mrousavy) - Creator of Nitro Modules and CEO of Margelo
483
490
  - [Nitro Modules](https://nitro.margelo.com/) - High-performance native module framework
484
491
  - [Margelo](https://margelo.com/) - Nitro Modules creators
492
+ - [Alvinotuya84](https://github.com/Alvinotuya84) - For the API inspiration I took from his repo [react-native-bluetooth-nitro-nexus](https://github.com/Alvinotuya84/react-native-bluetooth-nitro-nexus)
485
493
 
486
494
  ## 📞 Support
487
495
 
@@ -1,7 +1,6 @@
1
1
  import Foundation
2
2
  import CoreBluetooth
3
3
  import NitroModules
4
-
5
4
  /**
6
5
  * iOS implementation of the BLE Nitro Manager
7
6
  * Implements the HybridNativeBleNitroSpec protocol for Core Bluetooth operations
@@ -19,7 +18,7 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
19
18
  private var isCurrentlyScanning = false
20
19
  private var currentScanFilter: ScanFilter?
21
20
  private var centralManagerDelegate: BleCentralManagerDelegate!
22
-
21
+
23
22
  // MARK: - Initialization
24
23
  public override init() {
25
24
  super.init()
@@ -32,39 +31,27 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
32
31
  }
33
32
 
34
33
  // MARK: - State Management
35
- public func state(callback: @escaping (BLEState) -> Void) throws {
34
+ public func state() throws -> BLEState {
36
35
  let bleState = mapCBManagerStateToBLEState(centralManager.state)
37
- callback(bleState)
38
- }
39
-
40
- public func isBluetoothEnabled(callback: @escaping (Bool) -> Void) throws {
41
- let isEnabled = centralManager.state == .poweredOn
42
- callback(isEnabled)
36
+ return bleState
43
37
  }
44
38
 
45
39
  public func requestBluetoothEnable(callback: @escaping (Bool, String) -> Void) throws {
46
40
  // iOS doesn't allow programmatic Bluetooth enabling
47
41
  // We can only check the current state
48
- if centralManager.state == .poweredOn {
49
- callback(true, "")
50
- } else {
51
- callback(false, "Bluetooth must be enabled manually in Settings")
52
- }
42
+ callback(false, "Not supported")
53
43
  }
54
44
 
55
45
  public func subscribeToStateChange(
56
- stateCallback: @escaping (BLEState) -> Void,
57
- resultCallback: @escaping (Bool, String) -> Void
58
- ) throws {
46
+ stateCallback: @escaping (BLEState) -> Void
47
+ ) throws -> OperationResult {
59
48
  self.stateChangeCallback = stateCallback
60
- resultCallback(true, "")
49
+ return OperationResult(success: true, error: nil)
61
50
  }
62
51
 
63
- public func unsubscribeFromStateChange(
64
- resultCallback: @escaping (Bool, String) -> Void
65
- ) throws {
52
+ public func unsubscribeFromStateChange() throws -> OperationResult {
66
53
  self.stateChangeCallback = nil
67
- resultCallback(true, "")
54
+ return OperationResult(success: true, error: nil)
68
55
  }
69
56
 
70
57
  // MARK: - Scanning Operations
@@ -91,25 +78,25 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
91
78
  centralManager.scanForPeripherals(withServices: serviceUUIDs, options: options)
92
79
  }
93
80
 
94
- public func stopScan(callback: @escaping (Bool, String) -> Void) throws {
81
+ public func stopScan() throws -> Bool {
95
82
  centralManager.stopScan()
96
83
  isCurrentlyScanning = false
97
84
  scanCallback = nil
98
85
  currentScanFilter = nil
99
86
  // Keep discovered peripherals for potential connections
100
- callback(true, "")
87
+ return true
101
88
  }
102
89
 
103
- public func isScanning(callback: @escaping (Bool) -> Void) throws {
104
- callback(isCurrentlyScanning)
90
+ public func isScanning() throws -> Bool {
91
+ return isCurrentlyScanning
105
92
  }
106
93
 
107
94
  // MARK: - Device Discovery
108
- public func getConnectedDevices(callback: @escaping ([BLEDevice]) -> Void) throws {
95
+ public func getConnectedDevices(services: [String]) throws -> [BLEDevice] {
109
96
  var connectedDevices: [BLEDevice] = []
110
97
 
98
+ // First check our tracked connected peripherals
111
99
  for (deviceId, peripheral) in connectedPeripherals {
112
- // Create BLEDevice from connected peripheral
113
100
  let device = BLEDevice(
114
101
  id: deviceId,
115
102
  name: peripheral.name ?? "Unknown Device",
@@ -121,7 +108,58 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
121
108
  connectedDevices.append(device)
122
109
  }
123
110
 
124
- callback(connectedDevices)
111
+ // Check previously discovered peripherals to see if any are still connected
112
+ for (deviceId, peripheral) in discoveredPeripherals {
113
+ // Skip if we already know it's connected
114
+ if connectedPeripherals.keys.contains(deviceId) {
115
+ continue
116
+ }
117
+
118
+ // Check if this peripheral is actually connected by checking its state
119
+ if peripheral.state == .connected {
120
+ let device = BLEDevice(
121
+ id: deviceId,
122
+ name: peripheral.name ?? "Unknown Device",
123
+ rssi: 0,
124
+ manufacturerData: ManufacturerData(companyIdentifiers: []),
125
+ serviceUUIDs: peripheral.services?.map { $0.uuid.uuidString } ?? [],
126
+ isConnectable: true
127
+ )
128
+ connectedDevices.append(device)
129
+
130
+ // Add to our tracking dictionary
131
+ connectedPeripherals[deviceId] = peripheral
132
+ }
133
+ }
134
+
135
+ // Query system connected peripherals with specified services
136
+ let withServices: [CBUUID] = services.compactMap { CBUUID(string: $0) }
137
+
138
+ for service in withServices {
139
+ let peripherals = centralManager.retrieveConnectedPeripherals(withServices: [service])
140
+ for peripheral in peripherals {
141
+ let deviceId = peripheral.identifier.uuidString
142
+
143
+ // Only add if we don't already have it in our list
144
+ if !connectedPeripherals.keys.contains(deviceId) {
145
+ let device = BLEDevice(
146
+ id: deviceId,
147
+ name: peripheral.name ?? "Unknown Device",
148
+ rssi: 0,
149
+ manufacturerData: ManufacturerData(companyIdentifiers: []),
150
+ serviceUUIDs: peripheral.services?.map { $0.uuid.uuidString } ?? [],
151
+ isConnectable: true
152
+ )
153
+ connectedDevices.append(device)
154
+
155
+ // Add to our tracking dictionaries for future use
156
+ discoveredPeripherals[deviceId] = peripheral
157
+ connectedPeripherals[deviceId] = peripheral
158
+ }
159
+ }
160
+ }
161
+
162
+ return connectedDevices
125
163
  }
126
164
 
127
165
  // MARK: - Connection Management
@@ -164,12 +202,20 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
164
202
  centralManager.cancelPeripheralConnection(peripheral)
165
203
  }
166
204
 
167
- public func isConnected(deviceId: String, callback: @escaping (Bool) -> Void) throws {
205
+ public func isConnected(deviceId: String) throws -> Bool {
168
206
  if let peripheral = connectedPeripherals[deviceId] {
169
- callback(peripheral.state == .connected)
207
+ return peripheral.state == .connected
170
208
  } else {
171
- callback(false)
209
+ return false
210
+ }
211
+ }
212
+
213
+ public func requestMTU(deviceId: String, mtu: Double) throws -> Double {
214
+ guard let peripheral = connectedPeripherals[deviceId] else {
215
+ return Double(-1)
172
216
  }
217
+
218
+ return Double(peripheral.maximumWriteValueLength(for: .withoutResponse))
173
219
  }
174
220
 
175
221
  // MARK: - Service Discovery
@@ -183,35 +229,31 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
183
229
  peripheral.discoverServices(nil)
184
230
  }
185
231
 
186
- public func getServices(deviceId: String, callback: @escaping ([String]) -> Void) throws {
232
+ public func getServices(deviceId: String) throws -> [String] {
187
233
  guard let peripheral = connectedPeripherals[deviceId] else {
188
- callback([])
189
- return
234
+ return []
190
235
  }
191
236
 
192
237
  let serviceUUIDs = peripheral.services?.map { $0.uuid.uuidString } ?? []
193
- callback(serviceUUIDs)
238
+ return serviceUUIDs
194
239
  }
195
240
 
196
241
  public func getCharacteristics(
197
242
  deviceId: String,
198
243
  serviceId: String,
199
- callback: @escaping ([String]) -> Void
200
- ) throws {
244
+ ) throws -> [String] {
201
245
  guard let peripheral = connectedPeripherals[deviceId] else {
202
- callback([])
203
- return
246
+ return []
204
247
  }
205
248
 
206
249
  // Find service using CBUUID comparison
207
250
  let serviceUUID = CBUUID(string: serviceId)
208
251
  guard let service = peripheral.services?.first(where: { $0.uuid == serviceUUID }) else {
209
- callback([])
210
- return
252
+ return []
211
253
  }
212
254
 
213
255
  let characteristicUUIDs = service.characteristics?.map { $0.uuid.uuidString } ?? []
214
- callback(characteristicUUIDs)
256
+ return characteristicUUIDs
215
257
  }
216
258
 
217
259
  // MARK: - Characteristic Operations
@@ -219,16 +261,30 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
219
261
  deviceId: String,
220
262
  serviceId: String,
221
263
  characteristicId: String,
222
- callback: @escaping (Bool, [Double], String) -> Void
264
+ callback: @escaping (Bool, ArrayBuffer, String) -> Void
223
265
  ) throws {
224
266
  guard let characteristic = findCharacteristic(deviceId: deviceId, serviceId: serviceId, characteristicId: characteristicId) else {
225
- callback(false, [], "Characteristic not found")
267
+ do {
268
+ let emptyData = Data(capacity: 0)
269
+ let emptyBuffer = try ArrayBuffer.copy(data: emptyData)
270
+ callback(false, emptyBuffer, "Characteristic not found")
271
+ } catch {
272
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
273
+ callback(false, emptyBuffer, "Characteristic not found")
274
+ }
226
275
  return
227
276
  }
228
277
 
229
278
  // Ensure peripheral delegate exists
230
279
  guard let delegate = peripheralDelegates[deviceId] else {
231
- callback(false, [], "Device not properly connected or delegate not found")
280
+ do {
281
+ let emptyData = Data(capacity: 0)
282
+ let emptyBuffer = try ArrayBuffer.copy(data: emptyData)
283
+ callback(false, emptyBuffer, "Device not properly connected or delegate not found")
284
+ } catch {
285
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
286
+ callback(false, emptyBuffer, "Device not properly connected or delegate not found")
287
+ }
232
288
  return
233
289
  }
234
290
 
@@ -243,7 +299,7 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
243
299
  deviceId: String,
244
300
  serviceId: String,
245
301
  characteristicId: String,
246
- data: [Double],
302
+ data: ArrayBuffer,
247
303
  withResponse: Bool,
248
304
  callback: @escaping (Bool, String) -> Void
249
305
  ) throws {
@@ -252,7 +308,7 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
252
308
  return
253
309
  }
254
310
 
255
- let writeData = Data(data.map { UInt8($0) })
311
+ let writeData = data.toData(copyIfNeeded: true)
256
312
  let writeType: CBCharacteristicWriteType = withResponse ? .withResponse : .withoutResponse
257
313
 
258
314
  if withResponse {
@@ -275,7 +331,7 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
275
331
  deviceId: String,
276
332
  serviceId: String,
277
333
  characteristicId: String,
278
- updateCallback: @escaping (String, [Double]) -> Void,
334
+ updateCallback: @escaping (String, ArrayBuffer) -> Void,
279
335
  resultCallback: @escaping (Bool, String) -> Void
280
336
  ) throws {
281
337
  guard let characteristic = findCharacteristic(deviceId: deviceId, serviceId: serviceId, characteristicId: characteristicId) else {
@@ -485,17 +541,30 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
485
541
  }
486
542
 
487
543
  let companyId = manufacturerDataRaw.prefix(2).withUnsafeBytes { $0.load(as: UInt16.self) }
488
- let data = Array(manufacturerDataRaw.dropFirst(2)).map { Double($0) }
544
+ let dataBytes = Data(manufacturerDataRaw.dropFirst(2))
489
545
 
490
- let entry = ManufacturerDataEntry(
491
- id: String(companyId),
492
- data: data
493
- )
494
-
495
- return ManufacturerData(companyIdentifiers: [entry])
546
+ do {
547
+ let capacityData = Data(capacity: dataBytes.count)
548
+ let finalData = capacityData + dataBytes
549
+ let arrayBuffer = try ArrayBuffer.copy(data: finalData)
550
+
551
+ let entry = ManufacturerDataEntry(
552
+ id: String(companyId),
553
+ data: arrayBuffer
554
+ )
555
+
556
+ return ManufacturerData(companyIdentifiers: [entry])
557
+ } catch {
558
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
559
+ let entry = ManufacturerDataEntry(
560
+ id: String(companyId),
561
+ data: emptyBuffer
562
+ )
563
+ return ManufacturerData(companyIdentifiers: [entry])
564
+ }
496
565
  }
497
566
 
498
- public func openSettings() throws -> NitroModules.Promise<Void> {
567
+ public func openSettings() throws -> Promise<Void> {
499
568
  return Promise.async {
500
569
  if let url = URL(string: UIApplication.openSettingsURLString) {
501
570
  // Ask the system to open that URL.
@@ -20,13 +20,13 @@ class BlePeripheralDelegate: NSObject, CBPeripheralDelegate {
20
20
  var characteristicDiscoveryCallbacks: [String: (Bool, String) -> Void] = [:]
21
21
 
22
22
  // Operation callbacks - using CBUUID as key for reliable UUID matching
23
- var readCallbacks: [CBUUID: (Bool, [Double], String) -> Void] = [:]
23
+ var readCallbacks: [CBUUID: (Bool, ArrayBuffer, String) -> Void] = [:]
24
24
  var writeCallbacks: [CBUUID: (Bool, String) -> Void] = [:]
25
25
  var subscriptionCallbacks: [CBUUID: (Bool, String) -> Void] = [:]
26
26
  var unsubscriptionCallbacks: [CBUUID: (Bool, String) -> Void] = [:]
27
27
 
28
28
  // Notification callbacks
29
- var notificationCallbacks: [CBUUID: (String, [Double]) -> Void] = [:]
29
+ var notificationCallbacks: [CBUUID: (String, ArrayBuffer) -> Void] = [:]
30
30
 
31
31
  // MARK: - Initialization
32
32
  init(deviceId: String, manager: BleNitroBleManager) {
@@ -76,12 +76,33 @@ class BlePeripheralDelegate: NSObject, CBPeripheralDelegate {
76
76
  // Handle read callback using CBUUID - no normalization needed
77
77
  if let readCallback = readCallbacks[characteristicUUID] {
78
78
  if let error = error {
79
- readCallback(false, [], error.localizedDescription)
79
+ do {
80
+ let emptyData = Data(capacity: 0)
81
+ let emptyBuffer = try ArrayBuffer.copy(data: emptyData)
82
+ readCallback(false, emptyBuffer, error.localizedDescription)
83
+ } catch {
84
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
85
+ readCallback(false, emptyBuffer, error.localizedDescription)
86
+ }
80
87
  } else if let data = characteristic.value {
81
- let doubleArray = data.map { Double($0) }
82
- readCallback(true, doubleArray, "")
88
+ do {
89
+ let capacityData = Data(capacity: data.count)
90
+ let finalData = capacityData + data
91
+ let arrayBuffer = try ArrayBuffer.copy(data: finalData)
92
+ readCallback(true, arrayBuffer, "")
93
+ } catch {
94
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
95
+ readCallback(false, emptyBuffer, "Failed to create ArrayBuffer")
96
+ }
83
97
  } else {
84
- readCallback(false, [], "No data received")
98
+ do {
99
+ let emptyData = Data(capacity: 0)
100
+ let emptyBuffer = try ArrayBuffer.copy(data: emptyData)
101
+ readCallback(false, emptyBuffer, "No data received")
102
+ } catch {
103
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
104
+ readCallback(false, emptyBuffer, "No data received")
105
+ }
85
106
  }
86
107
  readCallbacks.removeValue(forKey: characteristicUUID)
87
108
  }
@@ -89,8 +110,15 @@ class BlePeripheralDelegate: NSObject, CBPeripheralDelegate {
89
110
  // Handle notification callback using CBUUID
90
111
  if let notificationCallback = notificationCallbacks[characteristicUUID],
91
112
  let data = characteristic.value {
92
- let doubleArray = data.map { Double($0) }
93
- notificationCallback(characteristicUUID.uuidString, doubleArray)
113
+ do {
114
+ let capacityData = Data(capacity: data.count)
115
+ let finalData = capacityData + data
116
+ let arrayBuffer = try ArrayBuffer.copy(data: finalData)
117
+ notificationCallback(characteristicUUID.uuidString, arrayBuffer)
118
+ } catch {
119
+ let emptyBuffer = try! ArrayBuffer.copy(data: Data())
120
+ notificationCallback(characteristicUUID.uuidString, emptyBuffer)
121
+ }
94
122
  }
95
123
  }
96
124
 
@@ -1,3 +1,4 @@
1
+ export type ByteArray = number[];
1
2
  export interface ScanFilter {
2
3
  serviceUUIDs?: string[];
3
4
  rssiThreshold?: number;
@@ -5,7 +6,7 @@ export interface ScanFilter {
5
6
  }
6
7
  export interface ManufacturerDataEntry {
7
8
  id: string;
8
- data: number[];
9
+ data: ByteArray;
9
10
  }
10
11
  export interface ManufacturerData {
11
12
  companyIdentifiers: ManufacturerDataEntry[];
@@ -22,9 +23,9 @@ export type ScanCallback = (device: BLEDevice) => void;
22
23
  export type ConnectionCallback = (success: boolean, deviceId: string, error: string) => void;
23
24
  export type DisconnectEventCallback = (deviceId: string, interrupted: boolean, error: string) => void;
24
25
  export type OperationCallback = (success: boolean, error: string) => void;
25
- export type CharacteristicUpdateCallback = (characteristicId: string, data: number[]) => void;
26
+ export type CharacteristicUpdateCallback = (characteristicId: string, data: ByteArray) => void;
26
27
  export type Subscription = {
27
- remove: () => Promise<void>;
28
+ remove: () => void;
28
29
  };
29
30
  export declare enum BLEState {
30
31
  Unknown = "Unknown",
@@ -52,22 +53,23 @@ export declare class BleNitro {
52
53
  * @param callback Callback function called when a device is found
53
54
  * @returns Promise resolving to success state
54
55
  */
55
- startScan(filter: ScanFilter | undefined, callback: ScanCallback): Promise<boolean>;
56
+ startScan(filter: ScanFilter | undefined, callback: ScanCallback): void;
56
57
  /**
57
58
  * Stop scanning for Bluetooth devices
58
59
  * @returns Promise resolving to success state
59
60
  */
60
- stopScan(): Promise<boolean>;
61
+ stopScan(): void;
61
62
  /**
62
63
  * Check if currently scanning for devices
63
64
  * @returns Promise resolving to scanning state
64
65
  */
65
- isScanning(): Promise<boolean>;
66
+ isScanning(): boolean;
66
67
  /**
67
68
  * Get all currently connected devices
68
- * @returns Promise resolving to array of connected devices
69
+ * @param services Optional list of service UUIDs to filter by
70
+ * @returns Array of connected devices
69
71
  */
70
- getConnectedDevices(): Promise<BLEDevice[]>;
72
+ getConnectedDevices(services?: string[]): BLEDevice[];
71
73
  /**
72
74
  * Connect to a Bluetooth device
73
75
  * @param deviceId ID of the device to connect to
@@ -80,13 +82,20 @@ export declare class BleNitro {
80
82
  * @param deviceId ID of the device to disconnect from
81
83
  * @returns Promise resolving when disconnected
82
84
  */
83
- disconnect(deviceId: string): Promise<boolean>;
85
+ disconnect(deviceId: string): Promise<void>;
84
86
  /**
85
87
  * Check if connected to a device
86
88
  * @param deviceId ID of the device to check
87
89
  * @returns Promise resolving to connection state
88
90
  */
89
- isConnected(deviceId: string): Promise<boolean>;
91
+ isConnected(deviceId: string): boolean;
92
+ /**
93
+ * Request a new MTU size
94
+ * @param deviceId ID of the device
95
+ * @param mtu New MTU size, min is 23, max is 517
96
+ * @returns On Android: new MTU size; on iOS: current MTU size as it is handled by iOS itself; on error: -1
97
+ */
98
+ requestMTU(deviceId: string, mtu: number): number;
90
99
  /**
91
100
  * Discover services for a connected device
92
101
  * @param deviceId ID of the device
@@ -105,25 +114,25 @@ export declare class BleNitro {
105
114
  * @param serviceId ID of the service
106
115
  * @returns Promise resolving to array of characteristic UUIDs
107
116
  */
108
- getCharacteristics(deviceId: string, serviceId: string): Promise<string[]>;
117
+ getCharacteristics(deviceId: string, serviceId: string): string[];
109
118
  /**
110
119
  * Read a characteristic value
111
120
  * @param deviceId ID of the device
112
121
  * @param serviceId ID of the service
113
122
  * @param characteristicId ID of the characteristic
114
- * @returns Promise resolving to the characteristic data as byte array
123
+ * @returns Promise resolving to the characteristic data as ByteArray
115
124
  */
116
- readCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<number[]>;
125
+ readCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<ByteArray>;
117
126
  /**
118
127
  * Write a value to a characteristic
119
128
  * @param deviceId ID of the device
120
129
  * @param serviceId ID of the service
121
130
  * @param characteristicId ID of the characteristic
122
- * @param data Data to write as an array of bytes
131
+ * @param data Data to write as ByteArray(number[])
123
132
  * @param withResponse Whether to wait for response
124
133
  * @returns Promise resolving when write is complete
125
134
  */
126
- writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, data: number[], withResponse?: boolean): Promise<boolean>;
135
+ writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, data: ByteArray, withResponse?: boolean): Promise<boolean>;
127
136
  /**
128
137
  * Subscribe to characteristic notifications
129
138
  * @param deviceId ID of the device
@@ -132,7 +141,7 @@ export declare class BleNitro {
132
141
  * @param callback Callback function called when notification is received
133
142
  * @returns Promise resolving when subscription is complete
134
143
  */
135
- subscribeToCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: CharacteristicUpdateCallback): Promise<Subscription>;
144
+ subscribeToCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: CharacteristicUpdateCallback): Subscription;
136
145
  /**
137
146
  * Unsubscribe from characteristic notifications
138
147
  * @param deviceId ID of the device
@@ -145,9 +154,9 @@ export declare class BleNitro {
145
154
  * Check if Bluetooth is enabled
146
155
  * @returns Promise resolving to Bluetooth state
147
156
  */
148
- isBluetoothEnabled(): Promise<boolean>;
157
+ isBluetoothEnabled(): boolean;
149
158
  /**
150
- * Request to enable Bluetooth
159
+ * Request to enable Bluetooth (Android only)
151
160
  * @returns Promise resolving when Bluetooth is enabled
152
161
  */
153
162
  requestBluetoothEnable(): Promise<boolean>;
@@ -156,7 +165,7 @@ export declare class BleNitro {
156
165
  * @returns Promise resolving to Bluetooth state
157
166
  * @see BLEState
158
167
  */
159
- state(): Promise<BLEState>;
168
+ state(): BLEState;
160
169
  /**
161
170
  * Subscribe to Bluetooth state changes
162
171
  * @param callback Callback function called when state changes
@@ -164,7 +173,7 @@ export declare class BleNitro {
164
173
  * @returns Promise resolving when subscription is complete
165
174
  * @see BLEState
166
175
  */
167
- subscribeToStateChange(callback: (state: BLEState) => void, emitInitial?: boolean): Promise<Subscription>;
176
+ subscribeToStateChange(callback: (state: BLEState) => void, emitInitial?: boolean): Subscription;
168
177
  /**
169
178
  * Open Bluetooth settings
170
179
  * @returns Promise resolving when settings are opened