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.
- package/README.md +25 -17
- package/ios/BleNitroBleManager.swift +126 -57
- package/ios/BlePeripheralDelegate.swift +36 -8
- package/lib/commonjs/index.d.ts +29 -20
- package/lib/commonjs/index.d.ts.map +1 -1
- package/lib/commonjs/index.js +113 -143
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +19 -14
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
- package/lib/commonjs/specs/NativeBleNitro.nitro.js.map +1 -1
- package/lib/index.d.ts +29 -20
- package/lib/index.js +112 -142
- package/lib/specs/NativeBleNitro.nitro.d.ts +19 -14
- package/nitrogen/generated/android/BleNitroOnLoad.cpp +6 -12
- package/nitrogen/generated/android/c++/JBLEDevice.hpp +3 -0
- package/nitrogen/generated/android/c++/JFunc_void_BLEDevice.hpp +3 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool_std__shared_ptr_ArrayBuffer__std__string.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__shared_ptr_ArrayBuffer_.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +111 -65
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +13 -13
- package/nitrogen/generated/android/c++/JManufacturerData.hpp +3 -0
- package/nitrogen/generated/android/c++/JManufacturerDataEntry.hpp +7 -15
- package/nitrogen/generated/android/c++/JOperationResult.hpp +58 -0
- 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
- 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
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt +20 -65
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/ManufacturerDataEntry.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/OperationResult.kt +32 -0
- package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.cpp +15 -39
- package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Bridge.hpp +108 -113
- package/nitrogen/generated/ios/BleNitro-Swift-Cxx-Umbrella.hpp +6 -0
- package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +57 -28
- 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
- package/nitrogen/generated/ios/swift/{Func_void_std__string_std__vector_double_.swift → Func_void_std__string_std__shared_ptr_ArrayBuffer_.swift} +11 -11
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +13 -13
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +84 -136
- package/nitrogen/generated/ios/swift/ManufacturerDataEntry.swift +5 -17
- package/nitrogen/generated/ios/swift/OperationResult.swift +64 -0
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +20 -14
- package/nitrogen/generated/shared/c++/ManufacturerDataEntry.hpp +8 -7
- package/nitrogen/generated/shared/c++/OperationResult.hpp +72 -0
- package/package.json +1 -1
- package/react-native.config.js +10 -2
- package/src/__tests__/index.test.ts +19 -22
- package/src/index.ts +147 -164
- package/src/specs/NativeBleNitro.nitro.ts +22 -14
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +0 -74
- package/nitrogen/generated/android/c++/JFunc_void_bool_std__vector_double__std__string.hpp +0 -86
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__vector_double_.hpp +0 -86
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_BLEDevice_.hpp +0 -99
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_std__string_.hpp +0 -93
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_bool.kt +0 -81
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_std__vector_BLEDevice_.kt +0 -81
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/Func_void_std__vector_std__string_.kt +0 -81
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +0 -47
- package/nitrogen/generated/ios/swift/Func_void_std__vector_BLEDevice_.swift +0 -47
- 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 =
|
|
86
|
+
const isEnabled = ble.isBluetoothEnabled();
|
|
87
87
|
|
|
88
88
|
// Get current Bluetooth state
|
|
89
|
-
const 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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
120
|
+
ble.stopScan();
|
|
121
121
|
|
|
122
122
|
// Check if currently scanning
|
|
123
|
-
const isScanning =
|
|
123
|
+
const isScanning = ble.isScanning();
|
|
124
124
|
|
|
125
125
|
// Get already connected devices
|
|
126
|
-
const connectedDevices =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
171
|
-
const characteristics2 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
34
|
+
public func state() throws -> BLEState {
|
|
36
35
|
let bleState = mapCBManagerStateToBLEState(centralManager.state)
|
|
37
|
-
|
|
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
|
-
|
|
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
|
-
|
|
58
|
-
) throws {
|
|
46
|
+
stateCallback: @escaping (BLEState) -> Void
|
|
47
|
+
) throws -> OperationResult {
|
|
59
48
|
self.stateChangeCallback = stateCallback
|
|
60
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
87
|
+
return true
|
|
101
88
|
}
|
|
102
89
|
|
|
103
|
-
public func isScanning(
|
|
104
|
-
|
|
90
|
+
public func isScanning() throws -> Bool {
|
|
91
|
+
return isCurrentlyScanning
|
|
105
92
|
}
|
|
106
93
|
|
|
107
94
|
// MARK: - Device Discovery
|
|
108
|
-
public func getConnectedDevices(
|
|
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
|
-
|
|
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
|
|
205
|
+
public func isConnected(deviceId: String) throws -> Bool {
|
|
168
206
|
if let peripheral = connectedPeripherals[deviceId] {
|
|
169
|
-
|
|
207
|
+
return peripheral.state == .connected
|
|
170
208
|
} else {
|
|
171
|
-
|
|
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
|
|
232
|
+
public func getServices(deviceId: String) throws -> [String] {
|
|
187
233
|
guard let peripheral = connectedPeripherals[deviceId] else {
|
|
188
|
-
|
|
189
|
-
return
|
|
234
|
+
return []
|
|
190
235
|
}
|
|
191
236
|
|
|
192
237
|
let serviceUUIDs = peripheral.services?.map { $0.uuid.uuidString } ?? []
|
|
193
|
-
|
|
238
|
+
return serviceUUIDs
|
|
194
239
|
}
|
|
195
240
|
|
|
196
241
|
public func getCharacteristics(
|
|
197
242
|
deviceId: String,
|
|
198
243
|
serviceId: String,
|
|
199
|
-
|
|
200
|
-
) throws {
|
|
244
|
+
) throws -> [String] {
|
|
201
245
|
guard let peripheral = connectedPeripherals[deviceId] else {
|
|
202
|
-
|
|
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
|
-
|
|
210
|
-
return
|
|
252
|
+
return []
|
|
211
253
|
}
|
|
212
254
|
|
|
213
255
|
let characteristicUUIDs = service.characteristics?.map { $0.uuid.uuidString } ?? []
|
|
214
|
-
|
|
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,
|
|
264
|
+
callback: @escaping (Bool, ArrayBuffer, String) -> Void
|
|
223
265
|
) throws {
|
|
224
266
|
guard let characteristic = findCharacteristic(deviceId: deviceId, serviceId: serviceId, characteristicId: characteristicId) else {
|
|
225
|
-
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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,
|
|
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
|
|
544
|
+
let dataBytes = Data(manufacturerDataRaw.dropFirst(2))
|
|
489
545
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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 ->
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
|
package/lib/commonjs/index.d.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
26
|
+
export type CharacteristicUpdateCallback = (characteristicId: string, data: ByteArray) => void;
|
|
26
27
|
export type Subscription = {
|
|
27
|
-
remove: () =>
|
|
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):
|
|
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():
|
|
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():
|
|
66
|
+
isScanning(): boolean;
|
|
66
67
|
/**
|
|
67
68
|
* Get all currently connected devices
|
|
68
|
-
* @
|
|
69
|
+
* @param services Optional list of service UUIDs to filter by
|
|
70
|
+
* @returns Array of connected devices
|
|
69
71
|
*/
|
|
70
|
-
getConnectedDevices():
|
|
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<
|
|
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):
|
|
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):
|
|
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
|
|
123
|
+
* @returns Promise resolving to the characteristic data as ByteArray
|
|
115
124
|
*/
|
|
116
|
-
readCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<
|
|
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
|
|
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:
|
|
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):
|
|
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():
|
|
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():
|
|
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):
|
|
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
|