react-native-ble-nitro 1.3.1 → 1.4.1
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 +37 -13
- package/android/src/main/java/com/margelo/nitro/co/zyke/ble/BleNitroBleManager.kt +48 -7
- package/ios/BleNitroBleManager.swift +95 -6
- package/ios/BlePeripheralDelegate.swift +13 -3
- package/lib/commonjs/index.d.ts +4 -194
- package/lib/commonjs/index.d.ts.map +1 -1
- package/lib/commonjs/index.js +6 -441
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/manager.d.ts +204 -0
- package/lib/commonjs/manager.d.ts.map +1 -0
- package/lib/commonjs/manager.js +471 -0
- package/lib/commonjs/manager.js.map +1 -0
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +4 -1
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
- package/lib/index.d.ts +4 -194
- package/lib/index.js +3 -436
- package/lib/manager.d.ts +203 -0
- package/lib/manager.js +457 -0
- package/lib/specs/NativeBleNitro.nitro.d.ts +4 -1
- package/nitrogen/generated/android/BleNitroOnLoad.cpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_BLEDevice_.hpp +102 -0
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +9 -4
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +2 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_std__vector_BLEDevice_.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 +38 -16
- package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +16 -10
- package/nitrogen/generated/ios/swift/Func_void_std__vector_BLEDevice_.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +2 -1
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +27 -5
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +7 -6
- package/package.json +9 -1
- package/src/__tests__/index.test.ts +75 -15
- package/src/index.ts +24 -609
- package/src/manager.ts +629 -0
- package/src/specs/NativeBleNitro.nitro.ts +6 -1
package/README.md
CHANGED
|
@@ -192,8 +192,7 @@ const data = await ble.readCharacteristic(deviceId, serviceUUID, characteristicU
|
|
|
192
192
|
|
|
193
193
|
// Example: Reading battery level
|
|
194
194
|
const batteryData = await ble.readCharacteristic(deviceId, '180f', '2a19');
|
|
195
|
-
const
|
|
196
|
-
const batteryLevel = batteryArray[0]; // First byte is battery percentage
|
|
195
|
+
const batteryLevel = batteryData[0]; // First byte is battery percentage
|
|
197
196
|
console.log('Battery level:', batteryLevel + '%');
|
|
198
197
|
```
|
|
199
198
|
|
|
@@ -201,23 +200,26 @@ console.log('Battery level:', batteryLevel + '%');
|
|
|
201
200
|
|
|
202
201
|
```typescript
|
|
203
202
|
// Write to a characteristic with response
|
|
204
|
-
const data =
|
|
205
|
-
await ble.writeCharacteristic(
|
|
203
|
+
const data = [0x01, 0x02, 0x03];
|
|
204
|
+
const result = await ble.writeCharacteristic(
|
|
206
205
|
deviceId,
|
|
207
206
|
serviceUUID,
|
|
208
207
|
characteristicUUID,
|
|
209
|
-
data
|
|
208
|
+
data, // Data as ArrayBuffer
|
|
210
209
|
true // withResponse = true (default)
|
|
211
210
|
);
|
|
211
|
+
// result is array of integers (may be empty depending on characteristic)
|
|
212
|
+
// Android returns the written data if withResponse=true and characteristic returns no data, on iOS it is an empty array
|
|
212
213
|
|
|
213
214
|
// Write without response (faster, no confirmation)
|
|
214
|
-
await ble.writeCharacteristic(
|
|
215
|
+
const emptyResult = await ble.writeCharacteristic(
|
|
215
216
|
deviceId,
|
|
216
217
|
serviceUUID,
|
|
217
218
|
characteristicUUID,
|
|
218
|
-
data
|
|
219
|
+
data,
|
|
219
220
|
false // withResponse = false
|
|
220
221
|
);
|
|
222
|
+
// emptyResult is always empty array
|
|
221
223
|
```
|
|
222
224
|
|
|
223
225
|
#### 📡 Characteristic Notifications
|
|
@@ -258,8 +260,7 @@ const subscription = ble.subscribeToCharacteristic(
|
|
|
258
260
|
HEART_RATE_SERVICE,
|
|
259
261
|
HEART_RATE_MEASUREMENT,
|
|
260
262
|
(_, data) => {
|
|
261
|
-
const
|
|
262
|
-
const heartRate = dataArray[1]; // Second byte contains BPM
|
|
263
|
+
const heartRate = data[1]; // Second byte contains BPM
|
|
263
264
|
console.log('Heart rate:', heartRate, 'BPM');
|
|
264
265
|
}
|
|
265
266
|
);
|
|
@@ -279,8 +280,7 @@ const batteryData = await ble.readCharacteristic(
|
|
|
279
280
|
BATTERY_SERVICE,
|
|
280
281
|
BATTERY_LEVEL_CHARACTERISTIC
|
|
281
282
|
);
|
|
282
|
-
const
|
|
283
|
-
const batteryPercentage = batteryArray[0];
|
|
283
|
+
const batteryPercentage = batteryData[0];
|
|
284
284
|
console.log('Battery:', batteryPercentage + '%');
|
|
285
285
|
```
|
|
286
286
|
|
|
@@ -291,12 +291,12 @@ const CUSTOM_SERVICE = 'your-custom-service-uuid';
|
|
|
291
291
|
const COMMAND_CHARACTERISTIC = 'your-command-characteristic-uuid';
|
|
292
292
|
|
|
293
293
|
// Send a custom command
|
|
294
|
-
const enableLedCommand =
|
|
294
|
+
const enableLedCommand = [0x01, 0x1f, 0x01]; // Your protocol
|
|
295
295
|
await ble.writeCharacteristic(
|
|
296
296
|
deviceId,
|
|
297
297
|
CUSTOM_SERVICE,
|
|
298
298
|
COMMAND_CHARACTERISTIC,
|
|
299
|
-
enableLedCommand
|
|
299
|
+
enableLedCommand
|
|
300
300
|
);
|
|
301
301
|
```
|
|
302
302
|
|
|
@@ -330,6 +330,30 @@ const fullUUIDs = BleNitro.normalizeGattUUIDs(['180d', '180f']);
|
|
|
330
330
|
// Returns: ['0000180d-0000-1000-8000-00805f9b34fb', '0000180f-0000-1000-8000-00805f9b34fb']
|
|
331
331
|
```
|
|
332
332
|
|
|
333
|
+
### iOS Restore State
|
|
334
|
+
|
|
335
|
+
There are two ways to handle state restoration on iOS:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Enable state restoration in BleNitro singleton
|
|
339
|
+
const ble = BleNitro.instance();
|
|
340
|
+
ble.onRestoreState((peripherals) => {
|
|
341
|
+
console.log('Restored peripherals:', peripherals);
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
// Or use BleNitroManager with options
|
|
347
|
+
// This way you have to assure that only one instance of BleNitroManager is created and that you always use this instance.
|
|
348
|
+
import { BleNitroManager, BLEDevice } from 'react-native-ble-nitro/manager';
|
|
349
|
+
|
|
350
|
+
const customBleInstance = new BleNitroManager({
|
|
351
|
+
onRestoreState: (peripherals: BLEDevice[]) => {
|
|
352
|
+
console.log('Restored peripherals:', peripherals);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
333
357
|
### TypeScript Types
|
|
334
358
|
|
|
335
359
|
```typescript
|
|
@@ -37,6 +37,7 @@ class BleNitroBleManager : HybridNativeBleNitroSpec() {
|
|
|
37
37
|
private var bluetoothAdapter: BluetoothAdapter? = null
|
|
38
38
|
private var stateCallback: ((state: BLEState) -> Unit)? = null
|
|
39
39
|
private var bluetoothStateReceiver: BroadcastReceiver? = null
|
|
40
|
+
private var restoreStateCallback: ((devices: List<BLEDevice>) -> Unit)? = null
|
|
40
41
|
|
|
41
42
|
// BLE Scanning
|
|
42
43
|
private var bleScanner: BluetoothLeScanner? = null
|
|
@@ -49,6 +50,9 @@ class BleNitroBleManager : HybridNativeBleNitroSpec() {
|
|
|
49
50
|
private val connectedDevices = ConcurrentHashMap<String, BluetoothGatt>()
|
|
50
51
|
private val deviceCallbacks = ConcurrentHashMap<String, DeviceCallbacks>()
|
|
51
52
|
|
|
53
|
+
// Write callback storage for proper response handling (key: deviceId:characteristicId)
|
|
54
|
+
private val writeCallbacks = ConcurrentHashMap<String, (Boolean, ArrayBuffer, String) -> Unit>()
|
|
55
|
+
|
|
52
56
|
// Helper class to store device callbacks
|
|
53
57
|
private data class DeviceCallbacks(
|
|
54
58
|
var connectCallback: ((success: Boolean, deviceId: String, error: String) -> Unit)? = null,
|
|
@@ -279,7 +283,23 @@ class BleNitroBleManager : HybridNativeBleNitroSpec() {
|
|
|
279
283
|
|
|
280
284
|
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
|
281
285
|
// Handle characteristic write result
|
|
282
|
-
|
|
286
|
+
val deviceId = gatt.device.address
|
|
287
|
+
val characteristicId = characteristic.uuid.toString()
|
|
288
|
+
val callbackKey = "$deviceId:$characteristicId"
|
|
289
|
+
|
|
290
|
+
writeCallbacks.remove(callbackKey)?.let { callback ->
|
|
291
|
+
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
292
|
+
// Get response data from characteristic value (may be null/empty for acknowledgments)
|
|
293
|
+
val responseData = characteristic.value ?: byteArrayOf()
|
|
294
|
+
val directBuffer = java.nio.ByteBuffer.allocateDirect(responseData.size)
|
|
295
|
+
directBuffer.put(responseData)
|
|
296
|
+
directBuffer.flip()
|
|
297
|
+
val arrayBuffer = ArrayBuffer.wrap(directBuffer)
|
|
298
|
+
callback(true, arrayBuffer, "")
|
|
299
|
+
} else {
|
|
300
|
+
callback(false, ArrayBuffer.allocate(0), "Write failed with status: $status")
|
|
301
|
+
}
|
|
302
|
+
}
|
|
283
303
|
}
|
|
284
304
|
|
|
285
305
|
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
|
|
@@ -304,6 +324,11 @@ class BleNitroBleManager : HybridNativeBleNitroSpec() {
|
|
|
304
324
|
}
|
|
305
325
|
}
|
|
306
326
|
|
|
327
|
+
override fun setRestoreStateCallback(callback: (restoredPeripherals: Array<BLEDevice>) -> Unit) {
|
|
328
|
+
restoreStateCallback = { devices -> callback(devices.toTypedArray()) }
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
|
|
307
332
|
// Scanning operations
|
|
308
333
|
override fun startScan(filter: com.margelo.nitro.co.zyke.ble.ScanFilter, callback: (device: BLEDevice?, error: String?) -> Unit) {
|
|
309
334
|
try {
|
|
@@ -640,24 +665,24 @@ class BleNitroBleManager : HybridNativeBleNitroSpec() {
|
|
|
640
665
|
characteristicId: String,
|
|
641
666
|
data: ArrayBuffer,
|
|
642
667
|
withResponse: Boolean,
|
|
643
|
-
callback: (success: Boolean, error: String) -> Unit
|
|
668
|
+
callback: (success: Boolean, responseData: ArrayBuffer, error: String) -> Unit
|
|
644
669
|
) {
|
|
645
670
|
try {
|
|
646
671
|
val gatt = connectedDevices[deviceId]
|
|
647
672
|
if (gatt == null) {
|
|
648
|
-
callback(false, "Device not connected")
|
|
673
|
+
callback(false, ArrayBuffer.allocate(0), "Device not connected")
|
|
649
674
|
return
|
|
650
675
|
}
|
|
651
676
|
|
|
652
677
|
val service = gatt.getService(UUID.fromString(serviceId))
|
|
653
678
|
if (service == null) {
|
|
654
|
-
callback(false, "Service not found")
|
|
679
|
+
callback(false, ArrayBuffer.allocate(0), "Service not found")
|
|
655
680
|
return
|
|
656
681
|
}
|
|
657
682
|
|
|
658
683
|
val characteristic = service.getCharacteristic(UUID.fromString(characteristicId))
|
|
659
684
|
if (characteristic == null) {
|
|
660
|
-
callback(false, "Characteristic not found")
|
|
685
|
+
callback(false, ArrayBuffer.allocate(0), "Characteristic not found")
|
|
661
686
|
return
|
|
662
687
|
}
|
|
663
688
|
|
|
@@ -673,11 +698,27 @@ class BleNitroBleManager : HybridNativeBleNitroSpec() {
|
|
|
673
698
|
BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
|
674
699
|
}
|
|
675
700
|
|
|
701
|
+
if (withResponse) {
|
|
702
|
+
// Store callback for when response comes back
|
|
703
|
+
val callbackKey = "$deviceId:$characteristicId"
|
|
704
|
+
writeCallbacks[callbackKey] = callback
|
|
705
|
+
}
|
|
706
|
+
|
|
676
707
|
val success = gatt.writeCharacteristic(characteristic)
|
|
677
|
-
|
|
708
|
+
|
|
709
|
+
if (!withResponse) {
|
|
710
|
+
// For no response, call callback immediately
|
|
711
|
+
callback(success, ArrayBuffer.allocate(0), if (success) "" else "Write operation failed")
|
|
712
|
+
} else if (!success) {
|
|
713
|
+
// If write initiation failed, remove callback and notify
|
|
714
|
+
val callbackKey = "$deviceId:$characteristicId"
|
|
715
|
+
writeCallbacks.remove(callbackKey)
|
|
716
|
+
callback(false, ArrayBuffer.allocate(0), "Write operation failed to initiate")
|
|
717
|
+
}
|
|
718
|
+
// If withResponse and success, wait for onCharacteristicWrite
|
|
678
719
|
|
|
679
720
|
} catch (e: Exception) {
|
|
680
|
-
callback(false, "Write error: ${e.message}")
|
|
721
|
+
callback(false, ArrayBuffer.allocate(0), "Write error: ${e.message}")
|
|
681
722
|
}
|
|
682
723
|
}
|
|
683
724
|
|
|
@@ -5,7 +5,13 @@ import NitroModules
|
|
|
5
5
|
* iOS implementation of the BLE Nitro Manager
|
|
6
6
|
* Implements the HybridNativeBleNitroSpec protocol for Core Bluetooth operations
|
|
7
7
|
*/
|
|
8
|
-
public class BleNitroBleManager:
|
|
8
|
+
public class BleNitroBleManager: HybridNativeBleNitroSpec_base, HybridNativeBleNitroSpec_protocol {
|
|
9
|
+
|
|
10
|
+
// MARK: - Constants
|
|
11
|
+
private static let restoreStateIdentifier = "react-native-ble-nitro"
|
|
12
|
+
|
|
13
|
+
// MARK: - Static Properties
|
|
14
|
+
private static var globalRestoreStateCallback: (([BLEDevice]) -> Void)?
|
|
9
15
|
|
|
10
16
|
// MARK: - Private Properties
|
|
11
17
|
private var centralManager: CBCentralManager!
|
|
@@ -18,6 +24,9 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
18
24
|
private var isCurrentlyScanning = false
|
|
19
25
|
private var currentScanFilter: ScanFilter?
|
|
20
26
|
private var centralManagerDelegate: BleCentralManagerDelegate!
|
|
27
|
+
|
|
28
|
+
// MARK: - Restore State Properties
|
|
29
|
+
private var restoreStateCallback: (([BLEDevice]) -> Void)?
|
|
21
30
|
|
|
22
31
|
// MARK: - Initialization
|
|
23
32
|
public override init() {
|
|
@@ -27,9 +36,16 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
27
36
|
|
|
28
37
|
private func setupCentralManager() {
|
|
29
38
|
centralManagerDelegate = BleCentralManagerDelegate(manager: self)
|
|
30
|
-
|
|
39
|
+
|
|
40
|
+
// Create options dictionary for central manager with fixed restore identifier
|
|
41
|
+
let options: [String: Any] = [
|
|
42
|
+
CBCentralManagerOptionRestoreIdentifierKey: BleNitroBleManager.restoreStateIdentifier
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
centralManager = CBCentralManager(delegate: centralManagerDelegate, queue: DispatchQueue.main, options: options)
|
|
31
46
|
}
|
|
32
47
|
|
|
48
|
+
|
|
33
49
|
// MARK: - State Management
|
|
34
50
|
public func state() throws -> BLEState {
|
|
35
51
|
let bleState = mapCBManagerStateToBLEState(centralManager.state)
|
|
@@ -54,6 +70,15 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
54
70
|
return OperationResult(success: true, error: nil)
|
|
55
71
|
}
|
|
56
72
|
|
|
73
|
+
// MARK: - Restore State Management
|
|
74
|
+
public func setRestoreStateCallback(callback: @escaping ([BLEDevice]) -> Void) throws {
|
|
75
|
+
print("🔄 setRestoreStateCallback called")
|
|
76
|
+
// Set both static and instance variables
|
|
77
|
+
BleNitroBleManager.globalRestoreStateCallback = callback
|
|
78
|
+
self.restoreStateCallback = callback
|
|
79
|
+
print("🔄 Callback set successfully")
|
|
80
|
+
}
|
|
81
|
+
|
|
57
82
|
// MARK: - Scanning Operations
|
|
58
83
|
public func startScan(filter: ScanFilter, callback: @escaping (BLEDevice?, String?) -> Void) throws {
|
|
59
84
|
guard centralManager.state == .poweredOn else {
|
|
@@ -305,10 +330,11 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
305
330
|
characteristicId: String,
|
|
306
331
|
data: ArrayBuffer,
|
|
307
332
|
withResponse: Bool,
|
|
308
|
-
callback: @escaping (Bool, String) -> Void
|
|
333
|
+
callback: @escaping (Bool, ArrayBuffer, String) -> Void
|
|
309
334
|
) throws {
|
|
310
335
|
guard let characteristic = findCharacteristic(deviceId: deviceId, serviceId: serviceId, characteristicId: characteristicId) else {
|
|
311
|
-
|
|
336
|
+
let emptyBuffer = try! ArrayBuffer.copy(data: Data())
|
|
337
|
+
callback(false, emptyBuffer, "Characteristic not found")
|
|
312
338
|
return
|
|
313
339
|
}
|
|
314
340
|
|
|
@@ -318,16 +344,20 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
318
344
|
if withResponse {
|
|
319
345
|
// Ensure peripheral delegate exists for response handling
|
|
320
346
|
guard let delegate = peripheralDelegates[deviceId] else {
|
|
321
|
-
|
|
347
|
+
let emptyBuffer = try! ArrayBuffer.copy(data: Data())
|
|
348
|
+
callback(false, emptyBuffer, "Device not properly connected or delegate not found")
|
|
322
349
|
return
|
|
323
350
|
}
|
|
324
351
|
delegate.writeCallbacks[characteristic.uuid] = callback
|
|
352
|
+
// Store written data for comparison
|
|
353
|
+
delegate.writtenData[characteristic.uuid] = writeData
|
|
325
354
|
}
|
|
326
355
|
|
|
327
356
|
characteristic.service?.peripheral?.writeValue(writeData, for: characteristic, type: writeType)
|
|
328
357
|
|
|
329
358
|
if !withResponse {
|
|
330
|
-
|
|
359
|
+
let emptyBuffer = try! ArrayBuffer.copy(data: Data())
|
|
360
|
+
callback(true, emptyBuffer, "")
|
|
331
361
|
}
|
|
332
362
|
}
|
|
333
363
|
|
|
@@ -407,6 +437,8 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
407
437
|
let characteristic = service.characteristics?.first(where: { $0.uuid == characteristicUUID }) else {
|
|
408
438
|
return nil
|
|
409
439
|
}
|
|
440
|
+
|
|
441
|
+
|
|
410
442
|
return characteristic
|
|
411
443
|
}
|
|
412
444
|
|
|
@@ -435,6 +467,59 @@ public class BleNitroBleManager: HybridNativeBleNitroSpec {
|
|
|
435
467
|
stateChangeCallback?(state)
|
|
436
468
|
}
|
|
437
469
|
|
|
470
|
+
internal func handleStateRestoration(_ dict: [String: Any]) {
|
|
471
|
+
// Restore connected peripherals
|
|
472
|
+
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] {
|
|
473
|
+
var restoredDevices: [BLEDevice] = []
|
|
474
|
+
|
|
475
|
+
for peripheral in peripherals {
|
|
476
|
+
let deviceId = peripheral.identifier.uuidString
|
|
477
|
+
|
|
478
|
+
// Add to our tracking dictionaries
|
|
479
|
+
discoveredPeripherals[deviceId] = peripheral
|
|
480
|
+
if peripheral.state == .connected {
|
|
481
|
+
connectedPeripherals[deviceId] = peripheral
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Create BLE device for the callback
|
|
485
|
+
let device = BLEDevice(
|
|
486
|
+
id: deviceId,
|
|
487
|
+
name: peripheral.name ?? "Restored Device",
|
|
488
|
+
rssi: 0, // RSSI not available for restored peripherals
|
|
489
|
+
manufacturerData: ManufacturerData(companyIdentifiers: []),
|
|
490
|
+
serviceUUIDs: peripheral.services?.map { $0.uuid.uuidString } ?? [],
|
|
491
|
+
isConnectable: true
|
|
492
|
+
)
|
|
493
|
+
restoredDevices.append(device)
|
|
494
|
+
|
|
495
|
+
// Set up delegate for restored peripheral
|
|
496
|
+
let delegate = BlePeripheralDelegate(deviceId: deviceId, manager: self)
|
|
497
|
+
peripheralDelegates[deviceId] = delegate
|
|
498
|
+
peripheral.delegate = delegate
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Call the restore state callback if set (prioritize static over instance)
|
|
502
|
+
let callback = BleNitroBleManager.globalRestoreStateCallback ?? restoreStateCallback
|
|
503
|
+
callback?(restoredDevices)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Restore scanning state if it was active
|
|
507
|
+
if let scanServiceUUIDs = dict[CBCentralManagerRestoredStateScanServicesKey] as? [CBUUID] {
|
|
508
|
+
// The system was scanning when the app was terminated
|
|
509
|
+
// We can choose to resume scanning or let the app decide
|
|
510
|
+
isCurrentlyScanning = true
|
|
511
|
+
|
|
512
|
+
// Note: We don't automatically resume scanning here to give the app control
|
|
513
|
+
// The app can check isScanning() and decide whether to resume or stop
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Restore scan options if available
|
|
517
|
+
if let scanOptions = dict[CBCentralManagerRestoredStateScanOptionsKey] as? [String: Any] {
|
|
518
|
+
// Store scan options for potential resume
|
|
519
|
+
// This information can be used if the app decides to resume scanning
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
438
523
|
internal func handleDeviceDiscovered(
|
|
439
524
|
_ peripheral: CBPeripheral,
|
|
440
525
|
advertisementData: [String: Any],
|
|
@@ -613,4 +698,8 @@ class BleCentralManagerDelegate: NSObject, CBCentralManagerDelegate {
|
|
|
613
698
|
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
|
614
699
|
manager?.handleDeviceDisconnected(peripheral, error: error)
|
|
615
700
|
}
|
|
701
|
+
|
|
702
|
+
func centralManager(_ central: CBCentralManager, willRestoreState dict: [String: Any]) {
|
|
703
|
+
manager?.handleStateRestoration(dict)
|
|
704
|
+
}
|
|
616
705
|
}
|
|
@@ -21,10 +21,13 @@ class BlePeripheralDelegate: NSObject, CBPeripheralDelegate {
|
|
|
21
21
|
|
|
22
22
|
// Operation callbacks - using CBUUID as key for reliable UUID matching
|
|
23
23
|
var readCallbacks: [CBUUID: (Bool, ArrayBuffer, String) -> Void] = [:]
|
|
24
|
-
var writeCallbacks: [CBUUID: (Bool, String) -> Void] = [:]
|
|
24
|
+
var writeCallbacks: [CBUUID: (Bool, ArrayBuffer, String) -> Void] = [:]
|
|
25
25
|
var subscriptionCallbacks: [CBUUID: (Bool, String) -> Void] = [:]
|
|
26
26
|
var unsubscriptionCallbacks: [CBUUID: (Bool, String) -> Void] = [:]
|
|
27
27
|
|
|
28
|
+
// Store written data for comparison
|
|
29
|
+
var writtenData: [CBUUID: Data] = [:]
|
|
30
|
+
|
|
28
31
|
// Notification callbacks
|
|
29
32
|
var notificationCallbacks: [CBUUID: (String, ArrayBuffer) -> Void] = [:]
|
|
30
33
|
|
|
@@ -133,11 +136,17 @@ class BlePeripheralDelegate: NSObject, CBPeripheralDelegate {
|
|
|
133
136
|
// Handle write callback using CBUUID
|
|
134
137
|
if let writeCallback = writeCallbacks[characteristicUUID] {
|
|
135
138
|
if let error = error {
|
|
136
|
-
|
|
139
|
+
let emptyBuffer = try! ArrayBuffer.copy(data: Data())
|
|
140
|
+
writeCallback(false, emptyBuffer, error.localizedDescription)
|
|
137
141
|
} else {
|
|
138
|
-
|
|
142
|
+
// For write operations in iOS, didWriteValueFor indicates successful acknowledgment
|
|
143
|
+
// Check if characteristic value was updated (may contain response data or written data)
|
|
144
|
+
let responseData = characteristic.value ?? Data()
|
|
145
|
+
let responseBuffer = try! ArrayBuffer.copy(data: responseData)
|
|
146
|
+
writeCallback(true, responseBuffer, "")
|
|
139
147
|
}
|
|
140
148
|
writeCallbacks.removeValue(forKey: characteristicUUID)
|
|
149
|
+
writtenData.removeValue(forKey: characteristicUUID)
|
|
141
150
|
}
|
|
142
151
|
}
|
|
143
152
|
|
|
@@ -195,6 +204,7 @@ class BlePeripheralDelegate: NSObject, CBPeripheralDelegate {
|
|
|
195
204
|
characteristicDiscoveryCallbacks.removeAll()
|
|
196
205
|
readCallbacks.removeAll()
|
|
197
206
|
writeCallbacks.removeAll()
|
|
207
|
+
writtenData.removeAll()
|
|
198
208
|
subscriptionCallbacks.removeAll()
|
|
199
209
|
unsubscriptionCallbacks.removeAll()
|
|
200
210
|
notificationCallbacks.removeAll()
|
package/lib/commonjs/index.d.ts
CHANGED
|
@@ -1,196 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
allowDuplicates?: boolean;
|
|
6
|
-
androidScanMode?: AndroidScanMode;
|
|
1
|
+
import { BleNitroManager } from "./manager";
|
|
2
|
+
export { type ByteArray, type ScanFilter, type BLEDevice, type ScanCallback, type ManufacturerDataEntry, type ManufacturerData, type ConnectionCallback, type DisconnectEventCallback, type OperationCallback, type CharacteristicUpdateCallback, type Subscription, type BleNitroManager, type BleNitroManagerOptions, BLEState, AndroidScanMode, } from "./manager";
|
|
3
|
+
export declare class BleNitro extends BleNitroManager {
|
|
4
|
+
static instance(): BleNitroManager;
|
|
7
5
|
}
|
|
8
|
-
export interface ManufacturerDataEntry {
|
|
9
|
-
id: string;
|
|
10
|
-
data: ByteArray;
|
|
11
|
-
}
|
|
12
|
-
export interface ManufacturerData {
|
|
13
|
-
companyIdentifiers: ManufacturerDataEntry[];
|
|
14
|
-
}
|
|
15
|
-
export interface BLEDevice {
|
|
16
|
-
id: string;
|
|
17
|
-
name: string;
|
|
18
|
-
rssi: number;
|
|
19
|
-
manufacturerData: ManufacturerData;
|
|
20
|
-
serviceUUIDs: string[];
|
|
21
|
-
isConnectable: boolean;
|
|
22
|
-
}
|
|
23
|
-
export type ScanCallback = (device: BLEDevice) => void;
|
|
24
|
-
export type RestoreStateCallback = (connectedPeripherals: BLEDevice[]) => void;
|
|
25
|
-
export type ConnectionCallback = (success: boolean, deviceId: string, error: string) => void;
|
|
26
|
-
export type DisconnectEventCallback = (deviceId: string, interrupted: boolean, error: string) => void;
|
|
27
|
-
export type OperationCallback = (success: boolean, error: string) => void;
|
|
28
|
-
export type CharacteristicUpdateCallback = (characteristicId: string, data: ByteArray) => void;
|
|
29
|
-
export type Subscription = {
|
|
30
|
-
remove: () => void;
|
|
31
|
-
};
|
|
32
|
-
export declare enum BLEState {
|
|
33
|
-
Unknown = "Unknown",
|
|
34
|
-
Resetting = "Resetting",
|
|
35
|
-
Unsupported = "Unsupported",
|
|
36
|
-
Unauthorized = "Unauthorized",
|
|
37
|
-
PoweredOff = "PoweredOff",
|
|
38
|
-
PoweredOn = "PoweredOn"
|
|
39
|
-
}
|
|
40
|
-
export declare enum AndroidScanMode {
|
|
41
|
-
LowLatency = "LowLatency",
|
|
42
|
-
Balanced = "Balanced",
|
|
43
|
-
LowPower = "LowPower",
|
|
44
|
-
Opportunistic = "Opportunistic"
|
|
45
|
-
}
|
|
46
|
-
export type BleNitroOptions = {
|
|
47
|
-
restoreStateIdentifier?: string;
|
|
48
|
-
onRestoreState?: RestoreStateCallback;
|
|
49
|
-
};
|
|
50
|
-
export declare class BleNitro {
|
|
51
|
-
private _isScanning;
|
|
52
|
-
private _connectedDevices;
|
|
53
|
-
static instance(): BleNitro;
|
|
54
|
-
/**
|
|
55
|
-
* Converts a 16- oder 32-Bit UUID to a 128-Bit UUID
|
|
56
|
-
*
|
|
57
|
-
* @param uuid 16-, 32- or 128-Bit UUID as string
|
|
58
|
-
* @returns Full 128-Bit UUID
|
|
59
|
-
*/
|
|
60
|
-
static normalizeGattUUID(uuid: string): string;
|
|
61
|
-
static normalizeGattUUIDs(uuids: string[]): string[];
|
|
62
|
-
/**
|
|
63
|
-
* Start scanning for Bluetooth devices
|
|
64
|
-
* @param filter Optional scan filter
|
|
65
|
-
* @param callback Callback function called when a device is found
|
|
66
|
-
* @returns Promise resolving to success state
|
|
67
|
-
*/
|
|
68
|
-
startScan(filter: ScanFilter | undefined, callback: ScanCallback, onError?: (error: string) => void): void;
|
|
69
|
-
/**
|
|
70
|
-
* Stop scanning for Bluetooth devices
|
|
71
|
-
* @returns Promise resolving to success state
|
|
72
|
-
*/
|
|
73
|
-
stopScan(): void;
|
|
74
|
-
/**
|
|
75
|
-
* Check if currently scanning for devices
|
|
76
|
-
* @returns Promise resolving to scanning state
|
|
77
|
-
*/
|
|
78
|
-
isScanning(): boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Get all currently connected devices
|
|
81
|
-
* @param services Optional list of service UUIDs to filter by
|
|
82
|
-
* @returns Array of connected devices
|
|
83
|
-
*/
|
|
84
|
-
getConnectedDevices(services?: string[]): BLEDevice[];
|
|
85
|
-
/**
|
|
86
|
-
* Connect to a Bluetooth device
|
|
87
|
-
* @param deviceId ID of the device to connect to
|
|
88
|
-
* @param onDisconnect Optional callback for disconnect events
|
|
89
|
-
* @returns Promise resolving when connected
|
|
90
|
-
*/
|
|
91
|
-
connect(deviceId: string, onDisconnect?: DisconnectEventCallback): Promise<string>;
|
|
92
|
-
/**
|
|
93
|
-
* Disconnect from a Bluetooth device
|
|
94
|
-
* @param deviceId ID of the device to disconnect from
|
|
95
|
-
* @returns Promise resolving when disconnected
|
|
96
|
-
*/
|
|
97
|
-
disconnect(deviceId: string): Promise<void>;
|
|
98
|
-
/**
|
|
99
|
-
* Check if connected to a device
|
|
100
|
-
* @param deviceId ID of the device to check
|
|
101
|
-
* @returns Promise resolving to connection state
|
|
102
|
-
*/
|
|
103
|
-
isConnected(deviceId: string): boolean;
|
|
104
|
-
/**
|
|
105
|
-
* Request a new MTU size
|
|
106
|
-
* @param deviceId ID of the device
|
|
107
|
-
* @param mtu New MTU size, min is 23, max is 517
|
|
108
|
-
* @returns On Android: new MTU size; on iOS: current MTU size as it is handled by iOS itself; on error: -1
|
|
109
|
-
*/
|
|
110
|
-
requestMTU(deviceId: string, mtu: number): number;
|
|
111
|
-
/**
|
|
112
|
-
* Discover services for a connected device
|
|
113
|
-
* @param deviceId ID of the device
|
|
114
|
-
* @returns Promise resolving when services are discovered
|
|
115
|
-
*/
|
|
116
|
-
discoverServices(deviceId: string): Promise<boolean>;
|
|
117
|
-
/**
|
|
118
|
-
* Get services for a connected device
|
|
119
|
-
* @param deviceId ID of the device
|
|
120
|
-
* @returns Promise resolving to array of service UUIDs
|
|
121
|
-
*/
|
|
122
|
-
getServices(deviceId: string): Promise<string[]>;
|
|
123
|
-
/**
|
|
124
|
-
* Get characteristics for a service
|
|
125
|
-
* @param deviceId ID of the device
|
|
126
|
-
* @param serviceId ID of the service
|
|
127
|
-
* @returns Promise resolving to array of characteristic UUIDs
|
|
128
|
-
*/
|
|
129
|
-
getCharacteristics(deviceId: string, serviceId: string): string[];
|
|
130
|
-
/**
|
|
131
|
-
* Read a characteristic value
|
|
132
|
-
* @param deviceId ID of the device
|
|
133
|
-
* @param serviceId ID of the service
|
|
134
|
-
* @param characteristicId ID of the characteristic
|
|
135
|
-
* @returns Promise resolving to the characteristic data as ArrayBuffer
|
|
136
|
-
*/
|
|
137
|
-
readCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<ByteArray>;
|
|
138
|
-
/**
|
|
139
|
-
* Write a value to a characteristic
|
|
140
|
-
* @param deviceId ID of the device
|
|
141
|
-
* @param serviceId ID of the service
|
|
142
|
-
* @param characteristicId ID of the characteristic
|
|
143
|
-
* @param data Data to write as ByteArray (number[])
|
|
144
|
-
* @param withResponse Whether to wait for response
|
|
145
|
-
* @returns Promise resolving when write is complete
|
|
146
|
-
*/
|
|
147
|
-
writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, data: ByteArray, withResponse?: boolean): Promise<boolean>;
|
|
148
|
-
/**
|
|
149
|
-
* Subscribe to characteristic notifications
|
|
150
|
-
* @param deviceId ID of the device
|
|
151
|
-
* @param serviceId ID of the service
|
|
152
|
-
* @param characteristicId ID of the characteristic
|
|
153
|
-
* @param callback Callback function called when notification is received
|
|
154
|
-
* @returns Promise resolving when subscription is complete
|
|
155
|
-
*/
|
|
156
|
-
subscribeToCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: CharacteristicUpdateCallback): Subscription;
|
|
157
|
-
/**
|
|
158
|
-
* Unsubscribe from characteristic notifications
|
|
159
|
-
* @param deviceId ID of the device
|
|
160
|
-
* @param serviceId ID of the service
|
|
161
|
-
* @param characteristicId ID of the characteristic
|
|
162
|
-
* @returns Promise resolving when unsubscription is complete
|
|
163
|
-
*/
|
|
164
|
-
unsubscribeFromCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<void>;
|
|
165
|
-
/**
|
|
166
|
-
* Check if Bluetooth is enabled
|
|
167
|
-
* @returns Promise resolving to Bluetooth state
|
|
168
|
-
*/
|
|
169
|
-
isBluetoothEnabled(): boolean;
|
|
170
|
-
/**
|
|
171
|
-
* Request to enable Bluetooth (Android only)
|
|
172
|
-
* @returns Promise resolving when Bluetooth is enabled
|
|
173
|
-
*/
|
|
174
|
-
requestBluetoothEnable(): Promise<boolean>;
|
|
175
|
-
/**
|
|
176
|
-
* Get the current Bluetooth state
|
|
177
|
-
* @returns Promise resolving to Bluetooth state
|
|
178
|
-
* @see BLEState
|
|
179
|
-
*/
|
|
180
|
-
state(): BLEState;
|
|
181
|
-
/**
|
|
182
|
-
* Subscribe to Bluetooth state changes
|
|
183
|
-
* @param callback Callback function called when state changes
|
|
184
|
-
* @param emitInitial Whether to emit initial state callback
|
|
185
|
-
* @returns Promise resolving when subscription is complete
|
|
186
|
-
* @see BLEState
|
|
187
|
-
*/
|
|
188
|
-
subscribeToStateChange(callback: (state: BLEState) => void, emitInitial?: boolean): Subscription;
|
|
189
|
-
/**
|
|
190
|
-
* Open Bluetooth settings
|
|
191
|
-
* @returns Promise resolving when settings are opened
|
|
192
|
-
*/
|
|
193
|
-
openSettings(): Promise<void>;
|
|
194
|
-
}
|
|
195
|
-
export declare const ble: BleNitro;
|
|
196
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,KAAK,4BAA4B,EACjC,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,QAAQ,EACR,eAAe,GAChB,MAAM,WAAW,CAAC;AAInB,qBAAa,QAAS,SAAQ,eAAe;WAC7B,QAAQ;CAMvB"}
|