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.
- package/README.md +17 -13
- package/android/src/main/java/com/margelo/nitro/co/zyke/ble/BleNitroBleManager.kt +81 -7
- package/ios/BleNitroBleManager.swift +30 -4
- package/ios/BlePeripheralDelegate.swift +29 -6
- package/lib/commonjs/manager.d.ts +11 -5
- package/lib/commonjs/manager.d.ts.map +1 -1
- package/lib/commonjs/manager.js +33 -9
- package/lib/commonjs/manager.js.map +1 -1
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +4 -1
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
- package/lib/manager.d.ts +11 -5
- package/lib/manager.js +33 -9
- package/lib/specs/NativeBleNitro.nitro.d.ts +4 -1
- package/nitrogen/generated/android/BleNitroOnLoad.cpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool_double_std__string.hpp +75 -0
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +8 -3
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +2 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_bool_double_std__string.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt +11 -2
- package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.cpp +8 -0
- package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.hpp +22 -0
- package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +7 -1
- package/nitrogen/generated/ios/swift/Func_void_bool_double_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +2 -1
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +21 -5
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +2 -1
- package/package.json +1 -1
- package/src/__tests__/index.test.ts +105 -1
- package/src/manager.ts +39 -11
- 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
|
-
|
|
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
|
|
126
|
+
private _restoredStateCallback: RestoreStateCallback | null = null;
|
|
127
127
|
private _restoredState: BLEDevice[] | null = null;
|
|
128
128
|
|
|
129
129
|
constructor(options?: BleNitroManagerOptions) {
|
|
130
|
-
this.
|
|
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.
|
|
137
|
-
this.
|
|
136
|
+
if (this._restoredStateCallback) {
|
|
137
|
+
this._restoredStateCallback(bleDevices);
|
|
138
138
|
} else {
|
|
139
139
|
this._restoredState = bleDevices;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
public
|
|
143
|
+
public onRestoredState(callback: RestoreStateCallback) {
|
|
144
144
|
if (this._restoredState) {
|
|
145
145
|
callback(this._restoredState);
|
|
146
146
|
this._restoredState = null;
|
|
147
147
|
}
|
|
148
|
-
this.
|
|
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
|
|
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<
|
|
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
|
-
|
|
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:
|
|
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
|
|