react-native-ble-nitro 1.11.0 → 1.12.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/android/src/main/java/com/margelo/nitro/co/zyke/ble/BleNitroBleManager.kt +58 -21
- package/ios/BleNitroBleManager.swift +60 -3
- package/ios/BlePeripheralDelegate.swift +68 -9
- package/lib/commonjs/index.d.ts +1 -1
- package/lib/commonjs/index.d.ts.map +1 -1
- package/lib/commonjs/index.js +2 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/manager.d.ts +17 -1
- package/lib/commonjs/manager.d.ts.map +1 -1
- package/lib/commonjs/manager.js +54 -9
- package/lib/commonjs/manager.js.map +1 -1
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts +3 -0
- package/lib/commonjs/specs/NativeBleNitro.nitro.d.ts.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/manager.d.ts +17 -1
- package/lib/manager.js +52 -8
- package/lib/specs/NativeBleNitro.nitro.d.ts +3 -0
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.cpp +9 -0
- package/nitrogen/generated/android/c++/JHybridNativeBleNitroSpec.hpp +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt +13 -0
- package/nitrogen/generated/ios/c++/HybridNativeBleNitroSpecSwift.hpp +14 -0
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridNativeBleNitroSpec_cxx.swift +28 -0
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridNativeBleNitroSpec.hpp +2 -0
- package/package.json +1 -1
- package/src/__tests__/index.test.ts +127 -0
- package/src/index.ts +1 -0
- package/src/manager.ts +81 -9
- package/src/specs/NativeBleNitro.nitro.ts +3 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeBleNitro.nitro.d.ts","sourceRoot":"","sources":["../../../src/specs/NativeBleNitro.nitro.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"NativeBleNitro.nitro.d.ts","sourceRoot":"","sources":["../../../src/specs/NativeBleNitro.nitro.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type ByteArray, type ScanFilter, type BLEDevice, type ScanCallback, type ManufacturerDataEntry, type ManufacturerData, type ConnectionCallback, type DisconnectEventCallback, type OperationCallback, type CharacteristicUpdateCallback, type Subscription, type AsyncSubscription, type BleNitroManagerOptions, BLEState, AndroidScanMode, BleNitroManager, } from "./manager";
|
|
1
|
+
export { type ByteArray, type ScanFilter, type BLEDevice, type ScanCallback, type ManufacturerDataEntry, type ManufacturerData, type ConnectionCallback, type DisconnectEventCallback, type OperationCallback, type CharacteristicUpdateCallback, type Subscription, type AsyncSubscription, type BleNitroManagerOptions, BLEState, AndroidScanMode, BleNitroManager, BleTimeoutError, } from "./manager";
|
|
2
2
|
export { BleNitro } from './singleton';
|
package/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { BLEState, AndroidScanMode, BleNitroManager, } from "./manager";
|
|
1
|
+
export { BLEState, AndroidScanMode, BleNitroManager, BleTimeoutError, } from "./manager";
|
|
2
2
|
export { BleNitro } from './singleton';
|
package/lib/manager.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { BLEDevice as NativeBLEDevice, BLEState as NativeBLEState, AndroidScanMode as NativeAndroidScanMode } from './specs/NativeBleNitro';
|
|
2
|
+
export declare class BleTimeoutError extends Error {
|
|
3
|
+
constructor(operation: string, ms: number);
|
|
4
|
+
}
|
|
2
5
|
export type ByteArray = number[];
|
|
3
6
|
export interface ScanFilter {
|
|
4
7
|
serviceUUIDs?: string[];
|
|
@@ -173,7 +176,10 @@ export declare class BleNitroManager {
|
|
|
173
176
|
*/
|
|
174
177
|
getCharacteristics(deviceId: string, serviceId: string): string[];
|
|
175
178
|
/**
|
|
176
|
-
* Get services and characteristics for a connected device
|
|
179
|
+
* Get services and characteristics for a connected device.
|
|
180
|
+
* Uses a native method that waits for both service and characteristic
|
|
181
|
+
* discovery to complete before reading, avoiding the CoreBluetooth race
|
|
182
|
+
* where didDiscoverServices may not re-fire for cached services.
|
|
177
183
|
* @param deviceId ID of the device
|
|
178
184
|
* @returns Promise resolving to array of service and characteristic UUIDs
|
|
179
185
|
* @see getServices
|
|
@@ -183,6 +189,8 @@ export declare class BleNitroManager {
|
|
|
183
189
|
uuid: string;
|
|
184
190
|
characteristics: string[];
|
|
185
191
|
}[]>;
|
|
192
|
+
private static readonly DISCOVERY_TIMEOUT_MS;
|
|
193
|
+
private _discoverServicesWithCharacteristics;
|
|
186
194
|
/**
|
|
187
195
|
* Read a characteristic value
|
|
188
196
|
* @param deviceId ID of the device
|
|
@@ -218,6 +226,14 @@ export declare class BleNitroManager {
|
|
|
218
226
|
* @returns Promise resolving when unsubscription is complete
|
|
219
227
|
*/
|
|
220
228
|
unsubscribeFromCharacteristic(deviceId: string, serviceId: string, characteristicId: string): Promise<void>;
|
|
229
|
+
/**
|
|
230
|
+
* Check if currently subscribed to a characteristic's notifications
|
|
231
|
+
* @param deviceId ID of the device
|
|
232
|
+
* @param serviceId ID of the service
|
|
233
|
+
* @param characteristicId ID of the characteristic
|
|
234
|
+
* @returns Boolean indicating if subscribed to notifications
|
|
235
|
+
*/
|
|
236
|
+
isSubscribedToCharacteristic(deviceId: string, serviceId: string, characteristicId: string): boolean;
|
|
221
237
|
/**
|
|
222
238
|
* Check if Bluetooth is enabled
|
|
223
239
|
* @returns returns Boolean according to Bluetooth state
|
package/lib/manager.js
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import BleNitroNativeFactory from './specs/NativeBleNitroFactory';
|
|
2
2
|
import { AndroidScanMode as NativeAndroidScanMode, } from './specs/NativeBleNitro';
|
|
3
|
+
export class BleTimeoutError extends Error {
|
|
4
|
+
constructor(operation, ms) {
|
|
5
|
+
super(`${operation} timed out after ${ms}ms`);
|
|
6
|
+
this.name = 'BleTimeoutError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function withTimeout(promise, ms, operation) {
|
|
10
|
+
let timer;
|
|
11
|
+
const timeout = new Promise((_, reject) => {
|
|
12
|
+
timer = setTimeout(() => reject(new BleTimeoutError(operation, ms)), ms);
|
|
13
|
+
});
|
|
14
|
+
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
15
|
+
}
|
|
3
16
|
export var BLEState;
|
|
4
17
|
(function (BLEState) {
|
|
5
18
|
BLEState["Unknown"] = "Unknown";
|
|
@@ -357,21 +370,39 @@ export class BleNitroManager {
|
|
|
357
370
|
return BleNitroManager.normalizeGattUUIDs(characteristics);
|
|
358
371
|
}
|
|
359
372
|
/**
|
|
360
|
-
* Get services and characteristics for a connected device
|
|
373
|
+
* Get services and characteristics for a connected device.
|
|
374
|
+
* Uses a native method that waits for both service and characteristic
|
|
375
|
+
* discovery to complete before reading, avoiding the CoreBluetooth race
|
|
376
|
+
* where didDiscoverServices may not re-fire for cached services.
|
|
361
377
|
* @param deviceId ID of the device
|
|
362
378
|
* @returns Promise resolving to array of service and characteristic UUIDs
|
|
363
379
|
* @see getServices
|
|
364
380
|
* @see getCharacteristics
|
|
365
381
|
*/
|
|
366
382
|
async getServicesWithCharacteristics(deviceId) {
|
|
367
|
-
await this.
|
|
368
|
-
const services =
|
|
369
|
-
return services.map((service) => {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
383
|
+
await this._discoverServicesWithCharacteristics(deviceId);
|
|
384
|
+
const services = this.Instance.getServices(deviceId);
|
|
385
|
+
return BleNitroManager.normalizeGattUUIDs(services).map((service) => ({
|
|
386
|
+
uuid: service,
|
|
387
|
+
characteristics: this.getCharacteristics(deviceId, service),
|
|
388
|
+
}));
|
|
389
|
+
}
|
|
390
|
+
_discoverServicesWithCharacteristics(deviceId) {
|
|
391
|
+
const inner = new Promise((resolve, reject) => {
|
|
392
|
+
if (!this.isConnected(deviceId)) {
|
|
393
|
+
reject(new Error('Device not connected'));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
this.Instance.discoverServicesWithCharacteristics(deviceId, (success, error) => {
|
|
397
|
+
if (success) {
|
|
398
|
+
resolve();
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
reject(new Error(error));
|
|
402
|
+
}
|
|
403
|
+
});
|
|
374
404
|
});
|
|
405
|
+
return withTimeout(inner, BleNitroManager.DISCOVERY_TIMEOUT_MS, 'discoverServicesWithCharacteristics');
|
|
375
406
|
}
|
|
376
407
|
/**
|
|
377
408
|
* Read a characteristic value
|
|
@@ -480,6 +511,18 @@ export class BleNitroManager {
|
|
|
480
511
|
});
|
|
481
512
|
});
|
|
482
513
|
}
|
|
514
|
+
/**
|
|
515
|
+
* Check if currently subscribed to a characteristic's notifications
|
|
516
|
+
* @param deviceId ID of the device
|
|
517
|
+
* @param serviceId ID of the service
|
|
518
|
+
* @param characteristicId ID of the characteristic
|
|
519
|
+
* @returns Boolean indicating if subscribed to notifications
|
|
520
|
+
*/
|
|
521
|
+
isSubscribedToCharacteristic(deviceId, serviceId, characteristicId) {
|
|
522
|
+
// No isConnected guard — both native implementations already return false
|
|
523
|
+
// for disconnected devices, and an extra check would introduce a TOCTOU race.
|
|
524
|
+
return this.Instance.isSubscribedToCharacteristic(deviceId, BleNitroManager.normalizeGattUUID(serviceId), BleNitroManager.normalizeGattUUID(characteristicId));
|
|
525
|
+
}
|
|
483
526
|
/**
|
|
484
527
|
* Check if Bluetooth is enabled
|
|
485
528
|
* @returns returns Boolean according to Bluetooth state
|
|
@@ -540,3 +583,4 @@ export class BleNitroManager {
|
|
|
540
583
|
return this.Instance.openSettings();
|
|
541
584
|
}
|
|
542
585
|
}
|
|
586
|
+
BleNitroManager.DISCOVERY_TIMEOUT_MS = 30000;
|
|
@@ -74,12 +74,15 @@ export interface NativeBleNitro extends HybridObject<{
|
|
|
74
74
|
requestMTU(deviceId: string, mtu: number): number;
|
|
75
75
|
readRSSI(deviceId: string, callback: ReadRSSICallback): void;
|
|
76
76
|
discoverServices(deviceId: string, callback: OperationCallback): void;
|
|
77
|
+
/** Discover services and wait for all characteristic discovery to complete before resolving. */
|
|
78
|
+
discoverServicesWithCharacteristics(deviceId: string, callback: OperationCallback): void;
|
|
77
79
|
getServices(deviceId: string): string[];
|
|
78
80
|
getCharacteristics(deviceId: string, serviceId: string): string[];
|
|
79
81
|
readCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: ReadCharacteristicCallback): void;
|
|
80
82
|
writeCharacteristic(deviceId: string, serviceId: string, characteristicId: string, data: BLEValue, withResponse: boolean, callback: WriteCharacteristicCallback): void;
|
|
81
83
|
subscribeToCharacteristic(deviceId: string, serviceId: string, characteristicId: string, updateCallback: CharacteristicCallback, completionCallback: OperationCallback): void;
|
|
82
84
|
unsubscribeFromCharacteristic(deviceId: string, serviceId: string, characteristicId: string, callback: OperationCallback): void;
|
|
85
|
+
isSubscribedToCharacteristic(deviceId: string, serviceId: string, characteristicId: string): boolean;
|
|
83
86
|
requestBluetoothEnable(callback: OperationCallback): void;
|
|
84
87
|
state(): BLEState;
|
|
85
88
|
subscribeToStateChange(stateCallback: StateCallback): OperationResult;
|
|
@@ -173,6 +173,10 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
173
173
|
static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* deviceId */, jni::alias_ref<JFunc_void_bool_std__string::javaobject> /* callback */)>("discoverServices_cxx");
|
|
174
174
|
method(_javaPart, jni::make_jstring(deviceId), JFunc_void_bool_std__string_cxx::fromCpp(callback));
|
|
175
175
|
}
|
|
176
|
+
void JHybridNativeBleNitroSpec::discoverServicesWithCharacteristics(const std::string& deviceId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) {
|
|
177
|
+
static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* deviceId */, jni::alias_ref<JFunc_void_bool_std__string::javaobject> /* callback */)>("discoverServicesWithCharacteristics_cxx");
|
|
178
|
+
method(_javaPart, jni::make_jstring(deviceId), JFunc_void_bool_std__string_cxx::fromCpp(callback));
|
|
179
|
+
}
|
|
176
180
|
std::vector<std::string> JHybridNativeBleNitroSpec::getServices(const std::string& deviceId) {
|
|
177
181
|
static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<jni::JArrayClass<jni::JString>>(jni::alias_ref<jni::JString> /* deviceId */)>("getServices");
|
|
178
182
|
auto __result = method(_javaPart, jni::make_jstring(deviceId));
|
|
@@ -217,6 +221,11 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
217
221
|
static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* deviceId */, jni::alias_ref<jni::JString> /* serviceId */, jni::alias_ref<jni::JString> /* characteristicId */, jni::alias_ref<JFunc_void_bool_std__string::javaobject> /* callback */)>("unsubscribeFromCharacteristic_cxx");
|
|
218
222
|
method(_javaPart, jni::make_jstring(deviceId), jni::make_jstring(serviceId), jni::make_jstring(characteristicId), JFunc_void_bool_std__string_cxx::fromCpp(callback));
|
|
219
223
|
}
|
|
224
|
+
bool JHybridNativeBleNitroSpec::isSubscribedToCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId) {
|
|
225
|
+
static const auto method = _javaPart->javaClassStatic()->getMethod<jboolean(jni::alias_ref<jni::JString> /* deviceId */, jni::alias_ref<jni::JString> /* serviceId */, jni::alias_ref<jni::JString> /* characteristicId */)>("isSubscribedToCharacteristic");
|
|
226
|
+
auto __result = method(_javaPart, jni::make_jstring(deviceId), jni::make_jstring(serviceId), jni::make_jstring(characteristicId));
|
|
227
|
+
return static_cast<bool>(__result);
|
|
228
|
+
}
|
|
220
229
|
void JHybridNativeBleNitroSpec::requestBluetoothEnable(const std::function<void(bool /* success */, const std::string& /* error */)>& callback) {
|
|
221
230
|
static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<JFunc_void_bool_std__string::javaobject> /* callback */)>("requestBluetoothEnable_cxx");
|
|
222
231
|
method(_javaPart, JFunc_void_bool_std__string_cxx::fromCpp(callback));
|
|
@@ -67,12 +67,14 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
67
67
|
double requestMTU(const std::string& deviceId, double mtu) override;
|
|
68
68
|
void readRSSI(const std::string& deviceId, const std::function<void(bool /* success */, double /* rssi */, const std::string& /* error */)>& callback) override;
|
|
69
69
|
void discoverServices(const std::string& deviceId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) override;
|
|
70
|
+
void discoverServicesWithCharacteristics(const std::string& deviceId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) override;
|
|
70
71
|
std::vector<std::string> getServices(const std::string& deviceId) override;
|
|
71
72
|
std::vector<std::string> getCharacteristics(const std::string& deviceId, const std::string& serviceId) override;
|
|
72
73
|
void readCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::function<void(bool /* success */, const std::shared_ptr<ArrayBuffer>& /* data */, const std::string& /* error */)>& callback) override;
|
|
73
74
|
void writeCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::shared_ptr<ArrayBuffer>& data, bool withResponse, const std::function<void(bool /* success */, const std::shared_ptr<ArrayBuffer>& /* responseData */, const std::string& /* error */)>& callback) override;
|
|
74
75
|
void subscribeToCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::function<void(const std::string& /* characteristicId */, const std::shared_ptr<ArrayBuffer>& /* data */)>& updateCallback, const std::function<void(bool /* success */, const std::string& /* error */)>& completionCallback) override;
|
|
75
76
|
void unsubscribeFromCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) override;
|
|
77
|
+
bool isSubscribedToCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId) override;
|
|
76
78
|
void requestBluetoothEnable(const std::function<void(bool /* success */, const std::string& /* error */)>& callback) override;
|
|
77
79
|
BLEState state() override;
|
|
78
80
|
OperationResult subscribeToStateChange(const std::function<void(BLEState /* state */)>& stateCallback) override;
|
package/nitrogen/generated/android/kotlin/com/margelo/nitro/co/zyke/ble/HybridNativeBleNitroSpec.kt
CHANGED
|
@@ -113,6 +113,15 @@ abstract class HybridNativeBleNitroSpec: HybridObject() {
|
|
|
113
113
|
return __result
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
abstract fun discoverServicesWithCharacteristics(deviceId: String, callback: (success: Boolean, error: String) -> Unit): Unit
|
|
117
|
+
|
|
118
|
+
@DoNotStrip
|
|
119
|
+
@Keep
|
|
120
|
+
private fun discoverServicesWithCharacteristics_cxx(deviceId: String, callback: Func_void_bool_std__string): Unit {
|
|
121
|
+
val __result = discoverServicesWithCharacteristics(deviceId, callback)
|
|
122
|
+
return __result
|
|
123
|
+
}
|
|
124
|
+
|
|
116
125
|
@DoNotStrip
|
|
117
126
|
@Keep
|
|
118
127
|
abstract fun getServices(deviceId: String): Array<String>
|
|
@@ -157,6 +166,10 @@ abstract class HybridNativeBleNitroSpec: HybridObject() {
|
|
|
157
166
|
return __result
|
|
158
167
|
}
|
|
159
168
|
|
|
169
|
+
@DoNotStrip
|
|
170
|
+
@Keep
|
|
171
|
+
abstract fun isSubscribedToCharacteristic(deviceId: String, serviceId: String, characteristicId: String): Boolean
|
|
172
|
+
|
|
160
173
|
abstract fun requestBluetoothEnable(callback: (success: Boolean, error: String) -> Unit): Unit
|
|
161
174
|
|
|
162
175
|
@DoNotStrip
|
|
@@ -184,6 +184,12 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
184
184
|
std::rethrow_exception(__result.error());
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
+
inline void discoverServicesWithCharacteristics(const std::string& deviceId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) override {
|
|
188
|
+
auto __result = _swiftPart.discoverServicesWithCharacteristics(deviceId, callback);
|
|
189
|
+
if (__result.hasError()) [[unlikely]] {
|
|
190
|
+
std::rethrow_exception(__result.error());
|
|
191
|
+
}
|
|
192
|
+
}
|
|
187
193
|
inline std::vector<std::string> getServices(const std::string& deviceId) override {
|
|
188
194
|
auto __result = _swiftPart.getServices(deviceId);
|
|
189
195
|
if (__result.hasError()) [[unlikely]] {
|
|
@@ -224,6 +230,14 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
224
230
|
std::rethrow_exception(__result.error());
|
|
225
231
|
}
|
|
226
232
|
}
|
|
233
|
+
inline bool isSubscribedToCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId) override {
|
|
234
|
+
auto __result = _swiftPart.isSubscribedToCharacteristic(deviceId, serviceId, characteristicId);
|
|
235
|
+
if (__result.hasError()) [[unlikely]] {
|
|
236
|
+
std::rethrow_exception(__result.error());
|
|
237
|
+
}
|
|
238
|
+
auto __value = std::move(__result.value());
|
|
239
|
+
return __value;
|
|
240
|
+
}
|
|
227
241
|
inline void requestBluetoothEnable(const std::function<void(bool /* success */, const std::string& /* error */)>& callback) override {
|
|
228
242
|
auto __result = _swiftPart.requestBluetoothEnable(callback);
|
|
229
243
|
if (__result.hasError()) [[unlikely]] {
|
|
@@ -25,12 +25,14 @@ public protocol HybridNativeBleNitroSpec_protocol: HybridObject {
|
|
|
25
25
|
func requestMTU(deviceId: String, mtu: Double) throws -> Double
|
|
26
26
|
func readRSSI(deviceId: String, callback: @escaping (_ success: Bool, _ rssi: Double, _ error: String) -> Void) throws -> Void
|
|
27
27
|
func discoverServices(deviceId: String, callback: @escaping (_ success: Bool, _ error: String) -> Void) throws -> Void
|
|
28
|
+
func discoverServicesWithCharacteristics(deviceId: String, callback: @escaping (_ success: Bool, _ error: String) -> Void) throws -> Void
|
|
28
29
|
func getServices(deviceId: String) throws -> [String]
|
|
29
30
|
func getCharacteristics(deviceId: String, serviceId: String) throws -> [String]
|
|
30
31
|
func readCharacteristic(deviceId: String, serviceId: String, characteristicId: String, callback: @escaping (_ success: Bool, _ data: ArrayBuffer, _ error: String) -> Void) throws -> Void
|
|
31
32
|
func writeCharacteristic(deviceId: String, serviceId: String, characteristicId: String, data: ArrayBuffer, withResponse: Bool, callback: @escaping (_ success: Bool, _ responseData: ArrayBuffer, _ error: String) -> Void) throws -> Void
|
|
32
33
|
func subscribeToCharacteristic(deviceId: String, serviceId: String, characteristicId: String, updateCallback: @escaping (_ characteristicId: String, _ data: ArrayBuffer) -> Void, completionCallback: @escaping (_ success: Bool, _ error: String) -> Void) throws -> Void
|
|
33
34
|
func unsubscribeFromCharacteristic(deviceId: String, serviceId: String, characteristicId: String, callback: @escaping (_ success: Bool, _ error: String) -> Void) throws -> Void
|
|
35
|
+
func isSubscribedToCharacteristic(deviceId: String, serviceId: String, characteristicId: String) throws -> Bool
|
|
34
36
|
func requestBluetoothEnable(callback: @escaping (_ success: Bool, _ error: String) -> Void) throws -> Void
|
|
35
37
|
func state() throws -> BLEState
|
|
36
38
|
func subscribeToStateChange(stateCallback: @escaping (_ state: BLEState) -> Void) throws -> OperationResult
|
|
@@ -370,6 +370,22 @@ open class HybridNativeBleNitroSpec_cxx {
|
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
+
@inline(__always)
|
|
374
|
+
public final func discoverServicesWithCharacteristics(deviceId: std.string, callback: bridge.Func_void_bool_std__string) -> bridge.Result_void_ {
|
|
375
|
+
do {
|
|
376
|
+
try self.__implementation.discoverServicesWithCharacteristics(deviceId: String(deviceId), callback: { () -> (Bool, String) -> Void in
|
|
377
|
+
let __wrappedFunction = bridge.wrap_Func_void_bool_std__string(callback)
|
|
378
|
+
return { (__success: Bool, __error: String) -> Void in
|
|
379
|
+
__wrappedFunction.call(__success, std.string(__error))
|
|
380
|
+
}
|
|
381
|
+
}())
|
|
382
|
+
return bridge.create_Result_void_()
|
|
383
|
+
} catch (let __error) {
|
|
384
|
+
let __exceptionPtr = __error.toCpp()
|
|
385
|
+
return bridge.create_Result_void_(__exceptionPtr)
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
373
389
|
@inline(__always)
|
|
374
390
|
public final func getServices(deviceId: std.string) -> bridge.Result_std__vector_std__string__ {
|
|
375
391
|
do {
|
|
@@ -475,6 +491,18 @@ open class HybridNativeBleNitroSpec_cxx {
|
|
|
475
491
|
}
|
|
476
492
|
}
|
|
477
493
|
|
|
494
|
+
@inline(__always)
|
|
495
|
+
public final func isSubscribedToCharacteristic(deviceId: std.string, serviceId: std.string, characteristicId: std.string) -> bridge.Result_bool_ {
|
|
496
|
+
do {
|
|
497
|
+
let __result = try self.__implementation.isSubscribedToCharacteristic(deviceId: String(deviceId), serviceId: String(serviceId), characteristicId: String(characteristicId))
|
|
498
|
+
let __resultCpp = __result
|
|
499
|
+
return bridge.create_Result_bool_(__resultCpp)
|
|
500
|
+
} catch (let __error) {
|
|
501
|
+
let __exceptionPtr = __error.toCpp()
|
|
502
|
+
return bridge.create_Result_bool_(__exceptionPtr)
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
478
506
|
@inline(__always)
|
|
479
507
|
public final func requestBluetoothEnable(callback: bridge.Func_void_bool_std__string) -> bridge.Result_void_ {
|
|
480
508
|
do {
|
|
@@ -28,12 +28,14 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
28
28
|
prototype.registerHybridMethod("requestMTU", &HybridNativeBleNitroSpec::requestMTU);
|
|
29
29
|
prototype.registerHybridMethod("readRSSI", &HybridNativeBleNitroSpec::readRSSI);
|
|
30
30
|
prototype.registerHybridMethod("discoverServices", &HybridNativeBleNitroSpec::discoverServices);
|
|
31
|
+
prototype.registerHybridMethod("discoverServicesWithCharacteristics", &HybridNativeBleNitroSpec::discoverServicesWithCharacteristics);
|
|
31
32
|
prototype.registerHybridMethod("getServices", &HybridNativeBleNitroSpec::getServices);
|
|
32
33
|
prototype.registerHybridMethod("getCharacteristics", &HybridNativeBleNitroSpec::getCharacteristics);
|
|
33
34
|
prototype.registerHybridMethod("readCharacteristic", &HybridNativeBleNitroSpec::readCharacteristic);
|
|
34
35
|
prototype.registerHybridMethod("writeCharacteristic", &HybridNativeBleNitroSpec::writeCharacteristic);
|
|
35
36
|
prototype.registerHybridMethod("subscribeToCharacteristic", &HybridNativeBleNitroSpec::subscribeToCharacteristic);
|
|
36
37
|
prototype.registerHybridMethod("unsubscribeFromCharacteristic", &HybridNativeBleNitroSpec::unsubscribeFromCharacteristic);
|
|
38
|
+
prototype.registerHybridMethod("isSubscribedToCharacteristic", &HybridNativeBleNitroSpec::isSubscribedToCharacteristic);
|
|
37
39
|
prototype.registerHybridMethod("requestBluetoothEnable", &HybridNativeBleNitroSpec::requestBluetoothEnable);
|
|
38
40
|
prototype.registerHybridMethod("state", &HybridNativeBleNitroSpec::state);
|
|
39
41
|
prototype.registerHybridMethod("subscribeToStateChange", &HybridNativeBleNitroSpec::subscribeToStateChange);
|
|
@@ -79,12 +79,14 @@ namespace margelo::nitro::co::zyke::ble {
|
|
|
79
79
|
virtual double requestMTU(const std::string& deviceId, double mtu) = 0;
|
|
80
80
|
virtual void readRSSI(const std::string& deviceId, const std::function<void(bool /* success */, double /* rssi */, const std::string& /* error */)>& callback) = 0;
|
|
81
81
|
virtual void discoverServices(const std::string& deviceId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) = 0;
|
|
82
|
+
virtual void discoverServicesWithCharacteristics(const std::string& deviceId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) = 0;
|
|
82
83
|
virtual std::vector<std::string> getServices(const std::string& deviceId) = 0;
|
|
83
84
|
virtual std::vector<std::string> getCharacteristics(const std::string& deviceId, const std::string& serviceId) = 0;
|
|
84
85
|
virtual void readCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::function<void(bool /* success */, const std::shared_ptr<ArrayBuffer>& /* data */, const std::string& /* error */)>& callback) = 0;
|
|
85
86
|
virtual void writeCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::shared_ptr<ArrayBuffer>& data, bool withResponse, const std::function<void(bool /* success */, const std::shared_ptr<ArrayBuffer>& /* responseData */, const std::string& /* error */)>& callback) = 0;
|
|
86
87
|
virtual void subscribeToCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::function<void(const std::string& /* characteristicId */, const std::shared_ptr<ArrayBuffer>& /* data */)>& updateCallback, const std::function<void(bool /* success */, const std::string& /* error */)>& completionCallback) = 0;
|
|
87
88
|
virtual void unsubscribeFromCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId, const std::function<void(bool /* success */, const std::string& /* error */)>& callback) = 0;
|
|
89
|
+
virtual bool isSubscribedToCharacteristic(const std::string& deviceId, const std::string& serviceId, const std::string& characteristicId) = 0;
|
|
88
90
|
virtual void requestBluetoothEnable(const std::function<void(bool /* success */, const std::string& /* error */)>& callback) = 0;
|
|
89
91
|
virtual BLEState state() = 0;
|
|
90
92
|
virtual OperationResult subscribeToStateChange(const std::function<void(BLEState /* state */)>& stateCallback) = 0;
|
package/package.json
CHANGED
|
@@ -10,12 +10,14 @@ const mockNativeInstance = {
|
|
|
10
10
|
requestMTU: jest.fn(),
|
|
11
11
|
readRSSI: jest.fn(),
|
|
12
12
|
discoverServices: jest.fn(),
|
|
13
|
+
discoverServicesWithCharacteristics: jest.fn(),
|
|
13
14
|
getServices: jest.fn(),
|
|
14
15
|
getCharacteristics: jest.fn(),
|
|
15
16
|
readCharacteristic: jest.fn(),
|
|
16
17
|
writeCharacteristic: jest.fn(),
|
|
17
18
|
subscribeToCharacteristic: jest.fn(),
|
|
18
19
|
unsubscribeFromCharacteristic: jest.fn(),
|
|
20
|
+
isSubscribedToCharacteristic: jest.fn(),
|
|
19
21
|
getConnectedDevices: jest.fn(),
|
|
20
22
|
requestBluetoothEnable: jest.fn(),
|
|
21
23
|
state: jest.fn(),
|
|
@@ -200,6 +202,90 @@ describe('BleNitro', () => {
|
|
|
200
202
|
expect(result).toEqual([0xAA, 0xBB, 0xCC]); // Response data as ByteArray
|
|
201
203
|
});
|
|
202
204
|
|
|
205
|
+
test('getServicesWithCharacteristics discovers and returns services with characteristics', async () => {
|
|
206
|
+
// First connect
|
|
207
|
+
mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
|
|
208
|
+
callback(true, id, '');
|
|
209
|
+
});
|
|
210
|
+
await BleManager.connect('device-svc');
|
|
211
|
+
|
|
212
|
+
mockNative.isConnected.mockImplementation((id: string) => {
|
|
213
|
+
return id === 'device-svc';
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Mock discoverServicesWithCharacteristics
|
|
217
|
+
mockNative.discoverServicesWithCharacteristics.mockImplementation((_deviceId: string, callback: (success: boolean, error: string) => void) => {
|
|
218
|
+
callback(true, '');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Mock getServices to return service UUIDs
|
|
222
|
+
mockNative.getServices.mockReturnValue(['0000180a-0000-1000-8000-00805f9b34fb', '0000180f-0000-1000-8000-00805f9b34fb']);
|
|
223
|
+
|
|
224
|
+
// Mock getCharacteristics per service
|
|
225
|
+
mockNative.getCharacteristics.mockImplementation((_deviceId: string, serviceId: string) => {
|
|
226
|
+
if (serviceId === '0000180a-0000-1000-8000-00805f9b34fb') {
|
|
227
|
+
return ['00002a29-0000-1000-8000-00805f9b34fb'];
|
|
228
|
+
}
|
|
229
|
+
return ['00002a19-0000-1000-8000-00805f9b34fb'];
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const result = await BleManager.getServicesWithCharacteristics('device-svc');
|
|
233
|
+
|
|
234
|
+
expect(mockNative.discoverServicesWithCharacteristics).toHaveBeenCalledWith(
|
|
235
|
+
'device-svc',
|
|
236
|
+
expect.any(Function)
|
|
237
|
+
);
|
|
238
|
+
expect(result).toHaveLength(2);
|
|
239
|
+
expect(result[0]).toHaveProperty('uuid');
|
|
240
|
+
expect(result[0]).toHaveProperty('characteristics');
|
|
241
|
+
expect(result[0].characteristics.length).toBeGreaterThan(0);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('getServicesWithCharacteristics rejects on discovery failure', async () => {
|
|
245
|
+
mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
|
|
246
|
+
callback(true, id, '');
|
|
247
|
+
});
|
|
248
|
+
await BleManager.connect('device-svc-fail');
|
|
249
|
+
|
|
250
|
+
mockNative.isConnected.mockImplementation((id: string) => {
|
|
251
|
+
return id === 'device-svc-fail';
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
mockNative.discoverServicesWithCharacteristics.mockImplementation((_deviceId: string, callback: (success: boolean, error: string) => void) => {
|
|
255
|
+
callback(false, 'Discovery failed');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
await expect(BleManager.getServicesWithCharacteristics('device-svc-fail')).rejects.toThrow('Discovery failed');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('getServicesWithCharacteristics rejects when not connected', async () => {
|
|
262
|
+
mockNative.isConnected.mockReturnValue(false);
|
|
263
|
+
|
|
264
|
+
await expect(BleManager.getServicesWithCharacteristics('unknown-device')).rejects.toThrow('Device not connected');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test('getServicesWithCharacteristics rejects with BleTimeoutError on timeout', async () => {
|
|
268
|
+
jest.useFakeTimers();
|
|
269
|
+
|
|
270
|
+
mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void) => {
|
|
271
|
+
callback(true, id, '');
|
|
272
|
+
});
|
|
273
|
+
await BleManager.connect('device-timeout');
|
|
274
|
+
|
|
275
|
+
mockNative.isConnected.mockImplementation((id: string) => id === 'device-timeout');
|
|
276
|
+
|
|
277
|
+
// Mock that NEVER calls its callback — simulates hung native discovery
|
|
278
|
+
mockNative.discoverServicesWithCharacteristics.mockImplementation(() => {});
|
|
279
|
+
|
|
280
|
+
const promise = BleManager.getServicesWithCharacteristics('device-timeout');
|
|
281
|
+
|
|
282
|
+
jest.advanceTimersByTime(30_000);
|
|
283
|
+
|
|
284
|
+
await expect(promise).rejects.toThrow('timed out after 30000ms');
|
|
285
|
+
|
|
286
|
+
jest.useRealTimers();
|
|
287
|
+
});
|
|
288
|
+
|
|
203
289
|
test('readCharacteristic works after connection', async () => {
|
|
204
290
|
// First connect
|
|
205
291
|
mockNative.connect.mockImplementation((id: string, callback: (success: boolean, deviceId: string, error: string) => void, _disconnectCallback?: (deviceId: string, interrupted: boolean, error: string) => void) => {
|
|
@@ -304,6 +390,47 @@ describe('BleNitro', () => {
|
|
|
304
390
|
expect(onDisconnect).toHaveBeenCalledWith(deviceId, true, 'Connection lost');
|
|
305
391
|
});
|
|
306
392
|
|
|
393
|
+
test('isSubscribedToCharacteristic delegates to native with normalized UUIDs', () => {
|
|
394
|
+
mockNative.isSubscribedToCharacteristic.mockReturnValueOnce(true);
|
|
395
|
+
|
|
396
|
+
const result = BleManager.isSubscribedToCharacteristic('device', 'service', 'char');
|
|
397
|
+
|
|
398
|
+
expect(result).toBe(true);
|
|
399
|
+
expect(mockNative.isSubscribedToCharacteristic).toHaveBeenCalledWith(
|
|
400
|
+
'device',
|
|
401
|
+
'0service-0000-1000-8000-00805f9b34fb',
|
|
402
|
+
'0000char-0000-1000-8000-00805f9b34fb'
|
|
403
|
+
);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
test('isSubscribedToCharacteristic returns false when not subscribed', () => {
|
|
407
|
+
mockNative.isSubscribedToCharacteristic.mockReturnValueOnce(false);
|
|
408
|
+
|
|
409
|
+
const result = BleManager.isSubscribedToCharacteristic('device', 'service', 'char');
|
|
410
|
+
|
|
411
|
+
expect(result).toBe(false);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
test('isSubscribedToCharacteristic delegates to native for unknown devices', () => {
|
|
415
|
+
// Native layer handles unknown/disconnected devices by returning false
|
|
416
|
+
mockNative.isSubscribedToCharacteristic.mockReturnValueOnce(false);
|
|
417
|
+
|
|
418
|
+
const result = BleManager.isSubscribedToCharacteristic('unknown-device', 'service', 'char');
|
|
419
|
+
|
|
420
|
+
expect(result).toBe(false);
|
|
421
|
+
expect(mockNative.isSubscribedToCharacteristic).toHaveBeenCalled();
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
test('isSubscribedToCharacteristic propagates native exception', () => {
|
|
425
|
+
mockNative.isSubscribedToCharacteristic.mockImplementationOnce(() => {
|
|
426
|
+
throw new Error('Native error');
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
expect(() =>
|
|
430
|
+
BleManager.isSubscribedToCharacteristic('device', 'service', 'char')
|
|
431
|
+
).toThrow('Native error');
|
|
432
|
+
});
|
|
433
|
+
|
|
307
434
|
test('readRSSI requires connected device', async () => {
|
|
308
435
|
await expect(
|
|
309
436
|
BleManager.readRSSI('device-not-connected')
|