react-native-ble-nitro 1.0.0-beta.0 → 1.0.0-beta.2

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.
@@ -57,6 +57,11 @@ class BleNitroBleManager(private val context: ReactApplicationContext) : HybridB
57
57
  private var logLevel: LogLevel = LogLevel.None
58
58
  private var isScanning = false
59
59
  private var scanCallback: ScanCallback? = null
60
+
61
+ // State restoration
62
+ private var restoreIdentifier: String? = null
63
+ private var isInitialized = false
64
+ private var restoredState: BleRestoredState? = null
60
65
  private var scanListener: ((NativeBleError?, NativeDevice?) -> Unit)? = null
61
66
  private var stateChangeListener: ((State) -> Unit)? = null
62
67
 
@@ -100,6 +105,104 @@ class BleNitroBleManager(private val context: ReactApplicationContext) : HybridB
100
105
  }
101
106
  }
102
107
 
108
+ override fun initialize(options: BleManagerNitroOptions): Promise<Unit> = Promise.resolve {
109
+ options.restoreStateIdentifier?.let { restoreId ->
110
+ this.restoreIdentifier = restoreId
111
+
112
+ // Attempt to restore previous state from SharedPreferences
113
+ restoreConnectionState(restoreId)
114
+
115
+ Log.d(TAG, "BleNitro: Initialized with restore state identifier: $restoreId")
116
+ }
117
+
118
+ this.isInitialized = true
119
+ Log.d(TAG, "BleNitro: BLE Manager initialized")
120
+ Unit
121
+ }
122
+
123
+ override fun getRestoredState(): Promise<BleRestoredState?> = Promise.resolve {
124
+ restoredState
125
+ }
126
+
127
+ private fun restoreConnectionState(restoreId: String) {
128
+ try {
129
+ val sharedPrefs = context.getSharedPreferences("BleNitro_$restoreId", Context.MODE_PRIVATE)
130
+ val connectedDevicesJson = sharedPrefs.getString("connected_devices", null)
131
+
132
+ connectedDevicesJson?.let { json ->
133
+ // Parse stored device IDs and attempt to reconnect
134
+ val deviceIds = json.split(",").filter { it.isNotEmpty() }
135
+
136
+ if (deviceIds.isNotEmpty()) {
137
+ Log.d(TAG, "BleNitro: Restoring ${deviceIds.size} devices")
138
+
139
+ deviceIds.forEach { deviceId ->
140
+ // Attempt to reconnect to previously connected devices
141
+ restoreDeviceConnection(deviceId)
142
+ }
143
+
144
+ // Store restored state (initially empty, will be populated as devices reconnect)
145
+ val initialDevices = deviceIds.mapNotNull { deviceId ->
146
+ bluetoothAdapter?.getRemoteDevice(deviceId)?.let { device ->
147
+ createNativeDevice(device, null, -1) // Initial state without GATT
148
+ }
149
+ }
150
+
151
+ if (initialDevices.isNotEmpty()) {
152
+ this.restoredState = BleRestoredState(initialDevices)
153
+ Log.d(TAG, "BleNitro: Stored restored state with ${initialDevices.size} devices")
154
+ }
155
+ }
156
+ }
157
+ } catch (e: Exception) {
158
+ Log.e(TAG, "BleNitro: Error restoring connection state", e)
159
+ }
160
+ }
161
+
162
+ private fun restoreDeviceConnection(deviceId: String) {
163
+ try {
164
+ val bluetoothDevice = bluetoothAdapter?.getRemoteDevice(deviceId)
165
+ bluetoothDevice?.let { device ->
166
+ Log.d(TAG, "BleNitro: Attempting to restore connection to $deviceId")
167
+
168
+ val gatt = device.connectGatt(context, true, object : BluetoothGattCallback() {
169
+ override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
170
+ if (newState == BluetoothProfile.STATE_CONNECTED) {
171
+ connectedDevices[deviceId] = gatt!!
172
+ Log.d(TAG, "BleNitro: Successfully restored connection to $deviceId")
173
+ } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
174
+ Log.d(TAG, "BleNitro: Failed to restore connection to $deviceId")
175
+ gatt?.close()
176
+ }
177
+ }
178
+ })
179
+
180
+ if (gatt != null) {
181
+ deviceCallbacks[deviceId] = gatt
182
+ }
183
+ }
184
+ } catch (e: Exception) {
185
+ Log.e(TAG, "BleNitro: Error restoring device connection for $deviceId", e)
186
+ }
187
+ }
188
+
189
+ private fun saveConnectionState() {
190
+ restoreIdentifier?.let { restoreId ->
191
+ try {
192
+ val sharedPrefs = context.getSharedPreferences("BleNitro_$restoreId", Context.MODE_PRIVATE)
193
+ val deviceIds = connectedDevices.keys.joinToString(",")
194
+
195
+ sharedPrefs.edit()
196
+ .putString("connected_devices", deviceIds)
197
+ .apply()
198
+
199
+ Log.d(TAG, "BleNitro: Saved connection state for ${connectedDevices.size} devices")
200
+ } catch (e: Exception) {
201
+ Log.e(TAG, "BleNitro: Error saving connection state", e)
202
+ }
203
+ }
204
+ }
205
+
103
206
  override fun setLogLevel(logLevel: LogLevel): Promise<LogLevel> = Promise.resolve {
104
207
  this.logLevel = logLevel
105
208
  logLevel
@@ -26,12 +26,28 @@ public class BleNitroBleManager: HybridBleManagerSpec, CBCentralManagerDelegate
26
26
  private var characteristicMonitors: [String: ((_ error: NativeBleError?, _ characteristic: NativeCharacteristic?) -> Void)] = [:]
27
27
  private var pendingOperations: [String: Any] = [:]
28
28
 
29
+ // State restoration
30
+ private var restoreIdentifier: String?
31
+ private var isInitialized = false
32
+ private var restoredState: BleRestoredState?
33
+
29
34
  // MARK: - Initialization
30
35
  public override init() {
31
36
  super.init()
37
+ // Initialize with default options - will be reconfigured in initialize() method
32
38
  self.centralManager = CBCentralManager(delegate: self, queue: nil)
33
39
  }
34
40
 
41
+ private func reinitializeCentralManager() {
42
+ // Create CBCentralManager with state restoration if identifier is provided
43
+ var options: [String: Any] = [:]
44
+ if let restoreId = restoreIdentifier {
45
+ options[CBCentralManagerOptionRestoreIdentifierKey] = restoreId
46
+ }
47
+
48
+ self.centralManager = CBCentralManager(delegate: self, queue: nil, options: options.isEmpty ? nil : options)
49
+ }
50
+
35
51
  public override var memorySize: Int {
36
52
  return MemorySize.MemorySize_estimate(self)
37
53
  }
@@ -51,6 +67,29 @@ public class BleNitroBleManager: HybridBleManagerSpec, CBCentralManagerDelegate
51
67
  }
52
68
  }
53
69
 
70
+ public func initialize(options: BleManagerNitroOptions) throws -> Promise<Void> {
71
+ return Promise.resolve(withBlock: {
72
+ if let restoreId = options.restoreStateIdentifier {
73
+ // Store the restore identifier
74
+ self.restoreIdentifier = restoreId
75
+
76
+ // Reinitialize the central manager with state restoration
77
+ self.reinitializeCentralManager()
78
+
79
+ print("BleNitro: Initialized with restore state identifier: \(restoreId)")
80
+ }
81
+
82
+ self.isInitialized = true
83
+ print("BleNitro: BLE Manager initialized")
84
+ })
85
+ }
86
+
87
+ public func getRestoredState() throws -> Promise<BleRestoredState?> {
88
+ return Promise.resolve(withBlock: {
89
+ return self.restoredState
90
+ })
91
+ }
92
+
54
93
  public func setLogLevel(logLevel: LogLevel) throws -> Promise<LogLevel> {
55
94
  return Promise.resolve(withBlock: {
56
95
  self.logLevel = logLevel
@@ -491,6 +530,40 @@ extension BleNitroBleManager: CBPeripheralDelegate {
491
530
  }
492
531
  }
493
532
  }
533
+
534
+ // MARK: - CBCentralManagerDelegate State Restoration
535
+
536
+ public func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
537
+ // Handle state restoration
538
+ if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] {
539
+ print("BleNitro: Restoring \(peripherals.count) peripherals")
540
+
541
+ // Add restored peripherals to our connected devices
542
+ for peripheral in peripherals {
543
+ let deviceId = peripheral.identifier.uuidString
544
+ connectedDevices[deviceId] = peripheral
545
+ peripheral.delegate = self
546
+
547
+ print("BleNitro: Restored peripheral: \(deviceId)")
548
+ }
549
+
550
+ // Store restored state for later retrieval
551
+ if !peripherals.isEmpty {
552
+ let restoredDevices = peripherals.map(createNativeDevice)
553
+ self.restoredState = BleRestoredState(connectedPeripherals: restoredDevices)
554
+ print("BleNitro: Stored restored state with \(restoredDevices.count) devices")
555
+ }
556
+ }
557
+ }
558
+
559
+ public func centralManagerDidUpdateState(_ central: CBCentralManager) {
560
+ let newState = convertCBManagerStateToState(central.state)
561
+
562
+ // Notify state change listener if available
563
+ stateChangeListener?(newState)
564
+
565
+ print("BleNitro: Central manager state changed to: \(central.state.rawValue)")
566
+ }
494
567
  }
495
568
 
496
569
  /**
@@ -38,7 +38,8 @@ export declare class BleManagerCompat {
38
38
  readCharacteristicForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, transactionId?: TransactionId): Promise<NativeCharacteristic>;
39
39
  writeCharacteristicWithResponseForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, base64Value: string, transactionId?: TransactionId): Promise<NativeCharacteristic>;
40
40
  writeCharacteristicWithoutResponseForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, base64Value: string, transactionId?: TransactionId): Promise<NativeCharacteristic>;
41
- monitorCharacteristicForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, listener: (error: any | null, characteristic: NativeCharacteristic | null) => void, transactionId?: TransactionId, subscriptionType?: 'notification' | 'indication'): Subscription;
41
+ monitorCharacteristicForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, listener: (error: any | null, characteristic: NativeCharacteristic | null) => void, // TODO: COMPAT! use proper error type like in react-native-ble-plx
42
+ transactionId?: TransactionId, subscriptionType?: 'notification' | 'indication'): Subscription;
42
43
  descriptorsForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID): Promise<NativeDescriptor[]>;
43
44
  readDescriptorForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, descriptorUUID: UUID, transactionId?: TransactionId): Promise<NativeDescriptor>;
44
45
  writeDescriptorForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID, characteristicUUID: UUID, descriptorUUID: UUID, valueBase64: string, transactionId?: TransactionId): Promise<NativeDescriptor>;
@@ -50,7 +50,8 @@ export class BleManagerCompat {
50
50
  }, emitCurrentState);
51
51
  }
52
52
  // Device scanning with compatibility wrappers
53
- async startDeviceScan(uuids, options, listener) {
53
+ async startDeviceScan(uuids, options, listener // TODO: COMPAT! remove any and move to BleError as react-native-ble-plx uses this type as well!
54
+ ) {
54
55
  return await this.bleManager.startDeviceScan(uuids, options, (error, device) => {
55
56
  listener(error, device ? new DeviceWrapper(this.createDeviceFromNative(device)) : null);
56
57
  });
@@ -76,7 +77,8 @@ export class BleManagerCompat {
76
77
  async isDeviceConnected(deviceIdentifier) {
77
78
  return await this.bleManager.isDeviceConnected(deviceIdentifier);
78
79
  }
79
- onDeviceDisconnected(deviceIdentifier, listener) {
80
+ onDeviceDisconnected(deviceIdentifier, listener // TODO: COMPAT! use propper error type like in react-native-ble-plx!!!
81
+ ) {
80
82
  return this.bleManager.onDeviceDisconnected(deviceIdentifier, (error, device) => {
81
83
  listener(error, device ? new DeviceWrapper(this.createDeviceFromNative(device)) : null);
82
84
  });
@@ -125,7 +127,8 @@ export class BleManagerCompat {
125
127
  async writeCharacteristicWithoutResponseForDevice(deviceIdentifier, serviceUUID, characteristicUUID, base64Value, transactionId) {
126
128
  return await this.bleManager.writeCharacteristicWithoutResponseForDevice(deviceIdentifier, serviceUUID, characteristicUUID, base64Value, transactionId);
127
129
  }
128
- monitorCharacteristicForDevice(deviceIdentifier, serviceUUID, characteristicUUID, listener, transactionId, subscriptionType) {
130
+ monitorCharacteristicForDevice(deviceIdentifier, serviceUUID, characteristicUUID, listener, // TODO: COMPAT! use proper error type like in react-native-ble-plx
131
+ transactionId, subscriptionType) {
129
132
  const nitroSubscriptionType = subscriptionType
130
133
  ? normalizeCharacteristicSubscriptionType(subscriptionType)
131
134
  : undefined;
@@ -5,8 +5,26 @@ import type { BleManagerOptions } from './specs/types.js';
5
5
  * This function maintains compatibility with react-native-ble-plx's BleManager constructor
6
6
  */
7
7
  export declare function createBleManager(options?: BleManagerOptions): BleManagerInterface;
8
+ /**
9
+ * Helper function to retrieve stored callbacks for a BleManager instance
10
+ * This is used internally when callbacks need to be invoked
11
+ */
12
+ export declare function getStoredCallbacks(manager: BleManagerInterface): {
13
+ restoreStateFunction?: (restoredState: any) => void;
14
+ errorCodesToMessagesMapping?: {
15
+ [key: number]: string;
16
+ };
17
+ } | undefined;
18
+ /**
19
+ * Helper function to get custom error message if available
20
+ * @param manager The BleManager instance
21
+ * @param errorCode The BLE error code
22
+ * @param defaultMessage Default error message
23
+ * @returns Custom message if available, otherwise default message
24
+ */
25
+ export declare function getCustomErrorMessage(manager: BleManagerInterface, errorCode: number, defaultMessage: string): string;
8
26
  /**
9
27
  * Legacy compatibility: Export a BleManager constructor function
10
28
  * This maintains compatibility with code that imports { BleManager } from 'react-native-ble-plx'
11
29
  */
12
- export declare const BleManager: any;
30
+ export declare const BleManager: (options?: BleManagerOptions) => BleManagerInterface;
@@ -1,4 +1,6 @@
1
1
  import { NitroModules } from 'react-native-nitro-modules';
2
+ // Store callbacks that can't be passed to Nitro
3
+ const storedCallbacks = new WeakMap();
2
4
  /**
3
5
  * Creates a BleManager instance using Nitro Modules
4
6
  * This function maintains compatibility with react-native-ble-plx's BleManager constructor
@@ -9,10 +11,59 @@ export function createBleManager(options) {
9
11
  throw new Error('Failed to create BleManager: Nitro module not found. ' +
10
12
  'Make sure react-native-ble-nitro is properly installed and linked.');
11
13
  }
12
- // If options are provided, we could initialize with them
13
- // For now, we return the module directly as Nitro handles the native initialization
14
+ // Initialize with options if provided
15
+ if (options) {
16
+ // Extract Nitro-compatible options
17
+ const nitroOptions = {
18
+ restoreStateIdentifier: options.restoreStateIdentifier,
19
+ };
20
+ // Store callbacks and mappings that can't be passed to Nitro
21
+ if (options.restoreStateFunction || options.errorCodesToMessagesMapping) {
22
+ storedCallbacks.set(BleManagerModule, {
23
+ restoreStateFunction: options.restoreStateFunction,
24
+ errorCodesToMessagesMapping: options.errorCodesToMessagesMapping,
25
+ });
26
+ }
27
+ // Note: initialize() is async but we need to maintain sync compatibility with react-native-ble-plx
28
+ // The initialization will happen asynchronously in the background
29
+ BleManagerModule.initialize(nitroOptions).then(async () => {
30
+ // Check for restored state and call the callback if available
31
+ if (options.restoreStateFunction) {
32
+ try {
33
+ const restoredState = await BleManagerModule.getRestoredState();
34
+ if (restoredState) {
35
+ options.restoreStateFunction(restoredState);
36
+ }
37
+ }
38
+ catch (error) {
39
+ console.warn('BleManager restore state callback failed:', error);
40
+ }
41
+ }
42
+ }).catch(error => {
43
+ console.warn('BleManager initialization failed:', error);
44
+ });
45
+ }
14
46
  return BleManagerModule;
15
47
  }
48
+ /**
49
+ * Helper function to retrieve stored callbacks for a BleManager instance
50
+ * This is used internally when callbacks need to be invoked
51
+ */
52
+ export function getStoredCallbacks(manager) {
53
+ return storedCallbacks.get(manager);
54
+ }
55
+ /**
56
+ * Helper function to get custom error message if available
57
+ * @param manager The BleManager instance
58
+ * @param errorCode The BLE error code
59
+ * @param defaultMessage Default error message
60
+ * @returns Custom message if available, otherwise default message
61
+ */
62
+ export function getCustomErrorMessage(manager, errorCode, defaultMessage) {
63
+ const callbacks = storedCallbacks.get(manager);
64
+ const customMessage = callbacks?.errorCodesToMessagesMapping?.[errorCode];
65
+ return customMessage || defaultMessage;
66
+ }
16
67
  /**
17
68
  * Legacy compatibility: Export a BleManager constructor function
18
69
  * This maintains compatibility with code that imports { BleManager } from 'react-native-ble-plx'
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './compatibility/constants.js';
2
2
  export * from './utils/index.js';
3
3
  export { BleManagerCompat as BleManager, createBleManagerCompat as createBleManager } from './BleManagerCompatFactory.js';
4
+ export { getCustomErrorMessage, getStoredCallbacks } from './BleManagerFactory.js';
4
5
  export * from './errors/BleError.js';
5
6
  export { DeviceWrapper as Device } from './compatibility/deviceWrapper.js';
6
7
  export type { BleManagerOptions, ScanOptions, ConnectionOptions, NativeBleError, NativeDevice, NativeService, NativeCharacteristic, NativeDescriptor, Subscription } from './specs/types.js';
package/lib/index.js CHANGED
@@ -4,6 +4,8 @@ export * from './compatibility/constants.js';
4
4
  export * from './utils/index.js';
5
5
  // Export the main BleManager instance with compatibility wrapper
6
6
  export { BleManagerCompat as BleManager, createBleManagerCompat as createBleManager } from './BleManagerCompatFactory.js';
7
+ // Export BleManager factory utilities (for internal use by error handling)
8
+ export { getCustomErrorMessage, getStoredCallbacks } from './BleManagerFactory.js';
7
9
  // Export error handling utilities
8
10
  export * from './errors/BleError.js';
9
11
  // Export device wrapper for compatibility
@@ -1,10 +1,18 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules';
2
2
  import type { State, LogLevel, UUID, DeviceId, TransactionId, ConnectionPriority, ScanOptions, ConnectionOptions, StateListener, DeviceScanListener, DeviceDisconnectedListener, CharacteristicMonitorListener, CharacteristicSubscriptionType, NativeDevice, NativeService, NativeCharacteristic, NativeDescriptor, Base64, Subscription } from './types.js';
3
+ export interface BleManagerNitroOptions {
4
+ restoreStateIdentifier?: string;
5
+ }
6
+ export interface BleRestoredState {
7
+ connectedPeripherals: NativeDevice[];
8
+ }
3
9
  export interface BleManager extends HybridObject<{
4
10
  ios: 'swift';
5
11
  android: 'kotlin';
6
12
  }> {
7
13
  destroy(): Promise<void>;
14
+ initialize(options: BleManagerNitroOptions): Promise<void>;
15
+ getRestoredState(): Promise<BleRestoredState | null>;
8
16
  setLogLevel(logLevel: LogLevel): Promise<LogLevel>;
9
17
  logLevel(): Promise<LogLevel>;
10
18
  cancelTransaction(transactionId: TransactionId): Promise<void>;
@@ -1,4 +1,4 @@
1
- import type { Base64 } from '../specs/types';
1
+ import type { Base64 } from '../specs/types.js';
2
2
  /**
3
3
  * Utility functions for Base64 encoding/decoding
4
4
  * Maintains compatibility with react-native-ble-plx Base64 operations
@@ -1,2 +1,2 @@
1
- export * from './uuid';
2
- export * from './base64';
1
+ export * from './uuid.js';
2
+ export * from './base64.js';
@@ -1,2 +1,2 @@
1
- export * from './uuid';
2
- export * from './base64';
1
+ export * from './uuid.js';
2
+ export * from './base64.js';
@@ -1,4 +1,4 @@
1
- import type { UUID } from '../specs/types';
1
+ import type { UUID } from '../specs/types.js';
2
2
  /**
3
3
  * Converts UUID to full 128bit, lowercase format which should be used to compare UUID values.
4
4
  * This function maintains 100% compatibility with react-native-ble-plx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ble-nitro",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "High-performance React Native BLE library built on Nitro Modules - drop-in replacement for react-native-ble-plx",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -76,7 +76,7 @@
76
76
  "nitro-codegen": "^0.26.4",
77
77
  "react-native": "^0.76.0",
78
78
  "ts-jest": "^29.4.0",
79
- "typescript": "^5.0.0"
79
+ "typescript": "^5.8.3"
80
80
  },
81
81
  "files": [
82
82
  "lib/",
@@ -93,7 +93,7 @@ export class BleManagerCompat {
93
93
  async startDeviceScan(
94
94
  uuids: UUID[] | null,
95
95
  options: ScanOptions | null,
96
- listener: (error: any | null, scannedDevice: DeviceWrapper | null) => void
96
+ listener: (error: any | null, scannedDevice: DeviceWrapper | null) => void // TODO: COMPAT! remove any and move to BleError as react-native-ble-plx uses this type as well!
97
97
  ): Promise<void> {
98
98
  return await this.bleManager.startDeviceScan(uuids, options, (error, device) => {
99
99
  listener(error, device ? new DeviceWrapper(this.createDeviceFromNative(device)) : null);
@@ -131,7 +131,7 @@ export class BleManagerCompat {
131
131
 
132
132
  onDeviceDisconnected(
133
133
  deviceIdentifier: DeviceId,
134
- listener: (error: any | null, device: DeviceWrapper | null) => void
134
+ listener: (error: any | null, device: DeviceWrapper | null) => void // TODO: COMPAT! use propper error type like in react-native-ble-plx!!!
135
135
  ): Subscription {
136
136
  return this.bleManager.onDeviceDisconnected(deviceIdentifier, (error, device) => {
137
137
  listener(error, device ? new DeviceWrapper(this.createDeviceFromNative(device)) : null);
@@ -255,7 +255,7 @@ export class BleManagerCompat {
255
255
  deviceIdentifier: DeviceId,
256
256
  serviceUUID: UUID,
257
257
  characteristicUUID: UUID,
258
- listener: (error: any | null, characteristic: NativeCharacteristic | null) => void,
258
+ listener: (error: any | null, characteristic: NativeCharacteristic | null) => void, // TODO: COMPAT! use proper error type like in react-native-ble-plx
259
259
  transactionId?: TransactionId,
260
260
  subscriptionType?: 'notification' | 'indication'
261
261
  ): Subscription {
@@ -324,7 +324,7 @@ export class BleManagerCompat {
324
324
  * Helper method to create a Device wrapper from NativeDevice data
325
325
  * This is a temporary method until we have proper Device Nitro objects
326
326
  */
327
- private createDeviceFromNative(nativeDevice: NativeDevice): any {
327
+ private createDeviceFromNative(nativeDevice: NativeDevice) {
328
328
  // This is a placeholder - in the actual implementation, we'd need to create
329
329
  // proper Nitro Device objects, but for now we'll work with the native data
330
330
  return {
@@ -1,7 +1,13 @@
1
1
  import { NitroModules } from 'react-native-nitro-modules';
2
- import type { BleManager as BleManagerInterface } from './specs/BleManager.nitro.js';
2
+ import type { BleManager as BleManagerInterface, BleManagerNitroOptions } from './specs/BleManager.nitro.js';
3
3
  import type { BleManagerOptions } from './specs/types.js';
4
4
 
5
+ // Store callbacks that can't be passed to Nitro
6
+ const storedCallbacks = new WeakMap<BleManagerInterface, {
7
+ restoreStateFunction?: (restoredState: any) => void;
8
+ errorCodesToMessagesMapping?: { [key: number]: string };
9
+ }>();
10
+
5
11
  /**
6
12
  * Creates a BleManager instance using Nitro Modules
7
13
  * This function maintains compatibility with react-native-ble-plx's BleManager constructor
@@ -16,15 +22,72 @@ export function createBleManager(options?: BleManagerOptions): BleManagerInterfa
16
22
  );
17
23
  }
18
24
 
19
- // If options are provided, we could initialize with them
20
- // For now, we return the module directly as Nitro handles the native initialization
25
+ // Initialize with options if provided
26
+ if (options) {
27
+ // Extract Nitro-compatible options
28
+ const nitroOptions: BleManagerNitroOptions = {
29
+ restoreStateIdentifier: options.restoreStateIdentifier,
30
+ };
31
+
32
+ // Store callbacks and mappings that can't be passed to Nitro
33
+ if (options.restoreStateFunction || options.errorCodesToMessagesMapping) {
34
+ storedCallbacks.set(BleManagerModule, {
35
+ restoreStateFunction: options.restoreStateFunction,
36
+ errorCodesToMessagesMapping: options.errorCodesToMessagesMapping,
37
+ });
38
+ }
39
+
40
+ // Note: initialize() is async but we need to maintain sync compatibility with react-native-ble-plx
41
+ // The initialization will happen asynchronously in the background
42
+ BleManagerModule.initialize(nitroOptions).then(async () => {
43
+ // Check for restored state and call the callback if available
44
+ if (options.restoreStateFunction) {
45
+ try {
46
+ const restoredState = await BleManagerModule.getRestoredState();
47
+ if (restoredState) {
48
+ options.restoreStateFunction(restoredState);
49
+ }
50
+ } catch (error) {
51
+ console.warn('BleManager restore state callback failed:', error);
52
+ }
53
+ }
54
+ }).catch(error => {
55
+ console.warn('BleManager initialization failed:', error);
56
+ });
57
+ }
58
+
21
59
  return BleManagerModule;
22
60
  }
23
61
 
62
+ /**
63
+ * Helper function to retrieve stored callbacks for a BleManager instance
64
+ * This is used internally when callbacks need to be invoked
65
+ */
66
+ export function getStoredCallbacks(manager: BleManagerInterface) {
67
+ return storedCallbacks.get(manager);
68
+ }
69
+
70
+ /**
71
+ * Helper function to get custom error message if available
72
+ * @param manager The BleManager instance
73
+ * @param errorCode The BLE error code
74
+ * @param defaultMessage Default error message
75
+ * @returns Custom message if available, otherwise default message
76
+ */
77
+ export function getCustomErrorMessage(
78
+ manager: BleManagerInterface,
79
+ errorCode: number,
80
+ defaultMessage: string
81
+ ): string {
82
+ const callbacks = storedCallbacks.get(manager);
83
+ const customMessage = callbacks?.errorCodesToMessagesMapping?.[errorCode];
84
+ return customMessage || defaultMessage;
85
+ }
86
+
24
87
  /**
25
88
  * Legacy compatibility: Export a BleManager constructor function
26
89
  * This maintains compatibility with code that imports { BleManager } from 'react-native-ble-plx'
27
90
  */
28
91
  export const BleManager = function(options?: BleManagerOptions): BleManagerInterface {
29
92
  return createBleManager(options);
30
- } as any;
93
+ } as (options?: BleManagerOptions) => BleManagerInterface;
@@ -16,7 +16,6 @@ import {
16
16
  normalizeCharacteristicSubscriptionType,
17
17
  State,
18
18
  LogLevel,
19
- type CharacteristicSubscriptionType
20
19
  } from '../../compatibility/enums';
21
20
  import {
22
21
  State as NitroState,
package/src/index.ts CHANGED
@@ -7,6 +7,9 @@ export * from './utils/index.js';
7
7
  // Export the main BleManager instance with compatibility wrapper
8
8
  export { BleManagerCompat as BleManager, createBleManagerCompat as createBleManager } from './BleManagerCompatFactory.js';
9
9
 
10
+ // Export BleManager factory utilities (for internal use by error handling)
11
+ export { getCustomErrorMessage, getStoredCallbacks } from './BleManagerFactory.js';
12
+
10
13
  // Export error handling utilities
11
14
  export * from './errors/BleError.js';
12
15
 
@@ -8,7 +8,6 @@ import type {
8
8
  ConnectionPriority,
9
9
  ScanOptions,
10
10
  ConnectionOptions,
11
- BleManagerOptions,
12
11
  StateListener,
13
12
  DeviceScanListener,
14
13
  DeviceDisconnectedListener,
@@ -18,16 +17,30 @@ import type {
18
17
  NativeService,
19
18
  NativeCharacteristic,
20
19
  NativeDescriptor,
21
- NativeBleError,
22
- BleRestoredState,
23
20
  Base64,
24
21
  Subscription
25
22
  } from './types.js';
26
23
 
24
+ // Nitro-compatible options interface (simplified without functions)
25
+ export interface BleManagerNitroOptions {
26
+ restoreStateIdentifier?: string;
27
+ }
28
+
29
+ // Interface for restored state data
30
+ export interface BleRestoredState {
31
+ connectedPeripherals: NativeDevice[];
32
+ }
33
+
27
34
  export interface BleManager extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
28
35
  // Lifecycle
29
36
  destroy(): Promise<void>;
30
37
 
38
+ // Initialization - Configure the BLE manager with options
39
+ initialize(options: BleManagerNitroOptions): Promise<void>;
40
+
41
+ // Get restored state if available (called after initialization)
42
+ getRestoredState(): Promise<BleRestoredState | null>;
43
+
31
44
  // Common operations
32
45
  setLogLevel(logLevel: LogLevel): Promise<LogLevel>;
33
46
  logLevel(): Promise<LogLevel>;
@@ -1,4 +1,4 @@
1
- import type { Base64 } from '../specs/types';
1
+ import type { Base64 } from '../specs/types.js';
2
2
 
3
3
  /**
4
4
  * Utility functions for Base64 encoding/decoding
@@ -1,2 +1,2 @@
1
- export * from './uuid';
2
- export * from './base64';
1
+ export * from './uuid.js';
2
+ export * from './base64.js';
package/src/utils/uuid.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { UUID } from '../specs/types';
1
+ import type { UUID } from '../specs/types.js';
2
2
 
3
3
  /**
4
4
  * Converts UUID to full 128bit, lowercase format which should be used to compare UUID values.