react-native-ble-nitro 1.4.0 → 1.5.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 (31) hide show
  1. package/README.md +17 -13
  2. package/android/src/main/java/com/margelo/nitro/co/zyke/ble/BleNitroBleManager.kt +81 -7
  3. package/ios/BleNitroBleManager.swift +30 -4
  4. package/ios/BlePeripheralDelegate.swift +29 -6
  5. package/lib/commonjs/manager.d.ts +11 -5
  6. package/lib/commonjs/manager.d.ts.map +1 -1
  7. package/lib/commonjs/manager.js +33 -9
  8. package/lib/commonjs/manager.js.map +1 -1
  9. package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +4 -1
  10. package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
  11. package/lib/manager.d.ts +11 -5
  12. package/lib/manager.js +33 -9
  13. package/lib/specs/NativeBleNitro.nitro.d.ts +4 -1
  14. package/nitrogen/generated/android/BleNitroOnLoad.cpp +2 -0
  15. package/nitrogen/generated/android/c++/JFunc_void_bool_double_std__string.hpp +75 -0
  16. package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +8 -3
  17. package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +2 -1
  18. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_bool_double_std__string.kt +81 -0
  19. package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt +11 -2
  20. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.cpp +8 -0
  21. package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.hpp +22 -0
  22. package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +7 -1
  23. package/nitrogen/generated/ios/swift/Func_void_bool_double_std__string.swift +47 -0
  24. package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +2 -1
  25. package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +21 -5
  26. package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.cpp +1 -0
  27. package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +2 -1
  28. package/package.json +1 -1
  29. package/src/__tests__/index.test.ts +105 -1
  30. package/src/manager.ts +39 -11
  31. package/src/specs/NativeBleNitro.nitro.ts +4 -1
@@ -10,6 +10,7 @@ jest.mock('../specs/NativeBleNitro', () => ({
10
10
  disconnect: jest.fn(),
11
11
  isConnected: jest.fn(),
12
12
  requestMTU: jest.fn(),
13
+ readRSSI: jest.fn(),
13
14
  discoverServices: jest.fn(),
14
15
  getServices: jest.fn(),
15
16
  getCharacteristics: jest.fn(),
@@ -121,10 +122,66 @@ describe('BleNitro', () => {
121
122
  test('writeCharacteristic requires connected device', async () => {
122
123
  const data = [1, 2, 3];
123
124
  await expect(
124
- BleManager.writeCharacteristic('device', 'service', 'char',data)
125
+ BleManager.writeCharacteristic('device', 'service', 'char', data)
125
126
  ).rejects.toThrow('Device not connected');
126
127
  });
127
128
 
129
+ test('writeCharacteristic without response returns empty array', async () => {
130
+ // First connect
131
+ mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
132
+ callback(true, id, '');
133
+ });
134
+ await BleManager.connect('device-write');
135
+
136
+ // Mock writeCharacteristic with new signature (success, responseData, error)
137
+ mockNative.writeCharacteristic.mockImplementation((_deviceId: string, _serviceId: string, _charId: string, _data: ArrayBuffer, withResponse: boolean, callback: (success: boolean, responseData: ArrayBuffer, error: string) => void) => {
138
+ // For withResponse=false, return empty ArrayBuffer
139
+ const emptyBuffer = new ArrayBuffer(0);
140
+ callback(true, emptyBuffer, '');
141
+ });
142
+
143
+ const data = [1, 2, 3];
144
+ const result = await BleManager.writeCharacteristic('device-write', 'service', 'char', data, false);
145
+
146
+ expect(mockNative.writeCharacteristic).toHaveBeenCalledWith(
147
+ 'device-write',
148
+ '0service-0000-1000-8000-00805f9b34fb',
149
+ '0000char-0000-1000-8000-00805f9b34fb',
150
+ expect.any(ArrayBuffer),
151
+ false,
152
+ expect.any(Function)
153
+ );
154
+ expect(result).toEqual([]); // Empty ByteArray for no response
155
+ });
156
+
157
+ test('writeCharacteristic with response returns response data', async () => {
158
+ // First connect
159
+ mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
160
+ callback(true, id, '');
161
+ });
162
+ await BleManager.connect('device-write-resp');
163
+
164
+ // Mock writeCharacteristic to return response data
165
+ mockNative.writeCharacteristic.mockImplementation((_deviceId: string, _serviceId: string, _charId: string, _data: ArrayBuffer, withResponse: boolean, callback: (success: boolean, responseData: ArrayBuffer, error: string) => void) => {
166
+ // For withResponse=true, return some response data
167
+ const responseData = new Uint8Array([0xAA, 0xBB, 0xCC]).buffer;
168
+ callback(true, responseData, '');
169
+ });
170
+
171
+ const data = [1, 2, 3];
172
+ const result = await BleManager.writeCharacteristic('device-write-resp', 'service', 'char', data, true);
173
+
174
+ expect(mockNative.writeCharacteristic).toHaveBeenCalledWith(
175
+ 'device-write-resp',
176
+ '0service-0000-1000-8000-00805f9b34fb',
177
+ '0000char-0000-1000-8000-00805f9b34fb',
178
+ expect.any(ArrayBuffer),
179
+ true,
180
+ expect.any(Function)
181
+ );
182
+ expect(result).toEqual([0xAA, 0xBB, 0xCC]); // Response data as ByteArray
183
+ });
184
+
128
185
  test('readCharacteristic works after connection', async () => {
129
186
  // First connect
130
187
  mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
@@ -220,4 +277,51 @@ describe('BleNitro', () => {
220
277
  await new Promise(resolve => setTimeout(resolve, 30));
221
278
  expect(onDisconnect).toHaveBeenCalledWith(deviceId, true, 'Connection lost');
222
279
  });
280
+
281
+ test('readRSSI requires connected device', async () => {
282
+ await expect(
283
+ BleManager.readRSSI('device-not-connected')
284
+ ).rejects.toThrow('Device not connected');
285
+ });
286
+
287
+ test('readRSSI works after connection', async () => {
288
+ // First connect
289
+ mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
290
+ callback(true, id, '');
291
+ });
292
+ await BleManager.connect('device-rssi');
293
+
294
+ // Mock readRSSI with new signature (success, rssi, error)
295
+ mockNative.readRSSI.mockImplementation((_deviceId: string, callback: (success: boolean, rssi: number, error: string) => void) => {
296
+ callback(true, -65, ''); // Mock RSSI value of -65 dBm
297
+ });
298
+
299
+ const rssi = await BleManager.readRSSI('device-rssi');
300
+
301
+ expect(mockNative.readRSSI).toHaveBeenCalledWith(
302
+ 'device-rssi',
303
+ expect.any(Function)
304
+ );
305
+ expect(rssi).toBe(-65);
306
+ });
307
+
308
+ test('readRSSI handles failure', async () => {
309
+ // First connect
310
+ mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
311
+ callback(true, id, '');
312
+ });
313
+ await BleManager.connect('device-rssi-fail');
314
+
315
+ // Mock readRSSI failure
316
+ mockNative.readRSSI.mockImplementation((_deviceId: string, callback: (success: boolean, rssi: number, error: string) => void) => {
317
+ callback(false, 0, 'RSSI read failed');
318
+ });
319
+
320
+ await expect(BleManager.readRSSI('device-rssi-fail')).rejects.toThrow('RSSI read failed');
321
+
322
+ expect(mockNative.readRSSI).toHaveBeenCalledWith(
323
+ 'device-rssi-fail',
324
+ expect.any(Function)
325
+ );
326
+ });
223
327
  });
package/src/manager.ts CHANGED
@@ -73,7 +73,7 @@ export enum AndroidScanMode {
73
73
  }
74
74
 
75
75
  export type BleNitroManagerOptions = {
76
- onRestoreState?: RestoreStateCallback;
76
+ onRestoredState?: RestoreStateCallback;
77
77
  };
78
78
 
79
79
  export function mapNativeBLEStateToBLEState(nativeState: NativeBLEState): BLEState {
@@ -123,29 +123,29 @@ export class BleNitroManager {
123
123
  private _isScanning: boolean = false;
124
124
  private _connectedDevices: { [deviceId: string]: boolean } = {};
125
125
 
126
- private _restoreStateCallback: RestoreStateCallback | null = null;
126
+ private _restoredStateCallback: RestoreStateCallback | null = null;
127
127
  private _restoredState: BLEDevice[] | null = null;
128
128
 
129
129
  constructor(options?: BleNitroManagerOptions) {
130
- this._restoreStateCallback = options?.onRestoreState || null;
130
+ this._restoredStateCallback = options?.onRestoredState || null;
131
131
  BleNitroNative.setRestoreStateCallback((peripherals: NativeBLEDevice[]) => this.onNativeRestoreStateCallback(peripherals));
132
132
  }
133
133
 
134
134
  private onNativeRestoreStateCallback(peripherals: NativeBLEDevice[]) {
135
135
  const bleDevices = peripherals.map((peripheral) => convertNativeBleDeviceToBleDevice(peripheral));
136
- if (this._restoreStateCallback) {
137
- this._restoreStateCallback(bleDevices);
136
+ if (this._restoredStateCallback) {
137
+ this._restoredStateCallback(bleDevices);
138
138
  } else {
139
139
  this._restoredState = bleDevices;
140
140
  }
141
141
  }
142
142
 
143
- public onRestoreState(callback: RestoreStateCallback) {
143
+ public onRestoredState(callback: RestoreStateCallback) {
144
144
  if (this._restoredState) {
145
145
  callback(this._restoredState);
146
146
  this._restoredState = null;
147
147
  }
148
- this._restoreStateCallback = callback;
148
+ this._restoredStateCallback = callback;
149
149
  }
150
150
 
151
151
  /**
@@ -330,6 +330,32 @@ export class BleNitroManager {
330
330
  return deviceMtu;
331
331
  }
332
332
 
333
+ /**
334
+ * Read RSSI for a connected device
335
+ * @param deviceId ID of the device
336
+ * @returns Promise resolving to RSSI value
337
+ */
338
+ public readRSSI(deviceId: string): Promise<number> {
339
+ return new Promise((resolve, reject) => {
340
+ // Check if connected first
341
+ if (!this._connectedDevices[deviceId]) {
342
+ reject(new Error('Device not connected'));
343
+ return;
344
+ }
345
+
346
+ BleNitroNative.readRSSI(
347
+ deviceId,
348
+ (success: boolean, rssi: number, error: string) => {
349
+ if (success) {
350
+ resolve(rssi);
351
+ } else {
352
+ reject(new Error(error));
353
+ }
354
+ }
355
+ );
356
+ });
357
+ }
358
+
333
359
  /**
334
360
  * Discover services for a connected device
335
361
  * @param deviceId ID of the device
@@ -441,7 +467,7 @@ export class BleNitroManager {
441
467
  * @param characteristicId ID of the characteristic
442
468
  * @param data Data to write as ByteArray (number[])
443
469
  * @param withResponse Whether to wait for response
444
- * @returns Promise resolving when write is complete
470
+ * @returns Promise resolving with response data (empty ByteArray when withResponse=false)
445
471
  */
446
472
  public writeCharacteristic(
447
473
  deviceId: string,
@@ -449,7 +475,7 @@ export class BleNitroManager {
449
475
  characteristicId: string,
450
476
  data: ByteArray,
451
477
  withResponse: boolean = true
452
- ): Promise<boolean> {
478
+ ): Promise<ByteArray> {
453
479
  return new Promise((resolve, reject) => {
454
480
  // Check if connected first
455
481
  if (!this._connectedDevices[deviceId]) {
@@ -463,9 +489,11 @@ export class BleNitroManager {
463
489
  BleNitroManager.normalizeGattUUID(characteristicId),
464
490
  byteArrayToArrayBuffer(data),
465
491
  withResponse,
466
- (success: boolean, error: string) => {
492
+ (success: boolean, responseData: ArrayBuffer, error: string) => {
467
493
  if (success) {
468
- resolve(true);
494
+ // Convert ArrayBuffer response to ByteArray
495
+ const responseByteArray = arrayBufferToByteArray(responseData);
496
+ resolve(responseByteArray);
469
497
  } else {
470
498
  reject(new Error(error));
471
499
  }
@@ -55,6 +55,8 @@ export type StateCallback = (state: BLEState) => void;
55
55
  export type BooleanCallback = (result: boolean) => void;
56
56
  export type StringArrayCallback = (result: string[]) => void;
57
57
  export type ReadCharacteristicCallback = (success: boolean, data: BLEValue, error: string) => void;
58
+ export type WriteCharacteristicCallback = (success: boolean, responseData: BLEValue, error: string) => void;
59
+ export type ReadRSSICallback = (success: boolean, rssi: number, error: string) => void;
58
60
  export type RestoreCallback = (restoredPeripherals: BLEDevice[]) => void;
59
61
 
60
62
  export type OperationResult = {
@@ -83,6 +85,7 @@ export interface NativeBleNitro extends HybridObject<{ ios: 'swift'; android: 'k
83
85
  disconnect(deviceId: string, callback: OperationCallback): void;
84
86
  isConnected(deviceId: string): boolean;
85
87
  requestMTU(deviceId: string, mtu: number): number;
88
+ readRSSI(deviceId: string, callback: ReadRSSICallback): void;
86
89
 
87
90
  // Service discovery
88
91
  discoverServices(deviceId: string, callback: OperationCallback): void;
@@ -91,7 +94,7 @@ export interface NativeBleNitro extends HybridObject<{ ios: 'swift'; android: 'k
91
94
 
92
95
  // Characteristic operations
93
96
  readCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: ReadCharacteristicCallback): void;
94
- writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, data: BLEValue, withResponse: boolean, callback: OperationCallback): void;
97
+ writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, data: BLEValue, withResponse: boolean, callback: WriteCharacteristicCallback): void;
95
98
  subscribeToCharacteristic(deviceId: string, serviceId: string, characteristicId: string, updateCallback: CharacteristicCallback, resultCallback: OperationCallback): void;
96
99
  unsubscribeFromCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: OperationCallback): void;
97
100