Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ buck-out/
*.jsbundle
/lib
/test_project
*.tsbuildinfo
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [3.5.2] - 2025-11-20

### Added

- Optional iOS BLE state restoration subspec (`react-native-ble-plx/Restoration`) with a Swift adapter that reuses CBCentralManager, reconnects restored peripherals, and registers with a host restoration registry when present.
- Config plugin options `iosEnableRestoration` and `iosRestorationIdentifier`; writes the identifier to Info.plist (`BlePlxRestoreIdentifier`) and injects the subspec into Podfile when enabled.
- Podfile injection test for the new plugin option.
- JS `BleManager` example now documents passing `restoreStateIdentifier` for restoration.

### Changed

- Obj-C bridge reuses a restored BleClientManager instance when available to maintain continuity after iOS background relaunch.

## [3.5.1] - 2025-07-11

### Fixed

- Fixed iOS null/nil handling in `createClient` method to prevent crashes when null values are passed from JavaScript
- Changed dispatch queue from `self.methodQueue` to `dispatch_get_main_queue()` for better thread safety
- Added proper null/nil checks for `filteredUUIDs` and `options` parameters in `startDeviceScan` method

## [3.5.0] - 2025-02-07

### Changed
Expand Down
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ for the old instructions or [migration guide](./docs/MIGRATION_V1.md).

| React Native | 3.1.2 |
| ------------ | ------------------ |
| 0.81.4 | :white_check_mark: |
| 0.74.1 | :white_check_mark: |
| 0.69.6 | :white_check_mark: |
| Expo 51 | :white_check_mark: |
Expand Down Expand Up @@ -102,6 +103,8 @@ The plugin provides props for extra customization. Every time you change the pro
- `neverForLocation` (_boolean_): Set to true only if you can strongly assert that your app never derives physical location from Bluetooth scan results. The location permission will be still required on older Android devices. Note, that some BLE beacons are filtered from the scan results. Android SDK 31+. Default `false`. _WARNING: This parameter is experimental and BLE might not work. Make sure to test before releasing to production._
- `modes` (_string[]_): Adds iOS `UIBackgroundModes` to the `Info.plist`. Options are: `peripheral`, and `central`. Defaults to undefined.
- `bluetoothAlwaysPermission` (_string | false_): Sets the iOS `NSBluetoothAlwaysUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission. Defaults to `Allow $(PRODUCT_NAME) to connect to bluetooth devices`.
- `iosEnableRestoration` (_boolean_): Opt-in to the iOS BLE state restoration subspec (disabled by default). When true, the Podfile will include `react-native-ble-plx/Restoration` and the adapter will register with a restoration registry if present.
- `iosRestorationIdentifier` (_string_): Custom CBCentralManager restoration identifier. Written to `Info.plist` as `BlePlxRestoreIdentifier` and passed to `BleManager` for state restoration. Defaults to `com.reactnativebleplx.restore`.

> Expo SDK 48 supports iOS 13+ which means `NSBluetoothPeripheralUsageDescription` is fully deprecated. It is no longer setup in `@config-plugins/react-native-ble-plx@5.0.0` and greater.

Expand All @@ -110,17 +113,19 @@ The plugin provides props for extra customization. Every time you change the pro
```json
{
"expo": {
"plugins": [
[
"react-native-ble-plx",
{
"isBackgroundEnabled": true,
"modes": ["peripheral", "central"],
"bluetoothAlwaysPermission": "Allow $(PRODUCT_NAME) to connect to bluetooth devices"
}
]
"plugins": [
[
"react-native-ble-plx",
{
"isBackgroundEnabled": true,
"modes": ["peripheral", "central"],
"bluetoothAlwaysPermission": "Allow $(PRODUCT_NAME) to connect to bluetooth devices",
"iosEnableRestoration": true,
"iosRestorationIdentifier": "com.example.myapp.bleplx"
}
]
}
]
}
}
```

Expand All @@ -139,6 +144,23 @@ The plugin provides props for extra customization. Every time you change the pro
`Background Modes` section.
- Pass `restoreStateIdentifier` and `restoreStateFunction` to `BleManager` constructor.

#### Optional: iOS BLE State Restoration (Restoration subspec)

- Opt-in via the config plugin: set `iosEnableRestoration: true` and optionally `iosRestorationIdentifier` to a stable string.
- The plugin writes `BlePlxRestoreIdentifier` into `Info.plist` and injects the `react-native-ble-plx/Restoration` subspec into your Podfile.
- In JS, pass the same identifier to `BleManager`:

```ts
const manager = new BleManager({
restoreStateIdentifier: 'com.example.myapp.bleplx',
restoreStateFunction: (restoredState) => {
// Rehydrate your app, reconnect devices, etc.
},
});
```

- The Restoration subspec exposes a Swift adapter (`BlePlxRestorationAdapter`) that will register with any restoration registry present in the host app (for example, a shared `BleRestorationRegistry`). If no registry is present, it is a no-op.

### Android ([example setup](https://github.com/Cierpliwy/SensorTag))

1. `npm install --save react-native-ble-plx`
Expand Down
5 changes: 4 additions & 1 deletion __tests__/BleManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const nativeOperationCancelledError =
'{"errorCode": 2, "attErrorCode": null, "iosErrorCode": null, "reason": null, "androidErrorCode": null}'

beforeEach(() => {
BleManager.sharedInstance = null
restoreStateFunction.mockClear()
Native.BleModule = {
createClient: jest.fn(),
destroyClient: jest.fn(),
Expand Down Expand Up @@ -44,6 +46,7 @@ beforeEach(() => {
ScanEvent: 'scan_event',
ReadEvent: 'read_event',
StateChangeEvent: 'state_change_event',
RestoreStateEvent: 'restore_state_event',
DisconnectionEvent: 'disconnection_event'
}
bleManager = new BleManager({
Expand Down Expand Up @@ -340,7 +343,7 @@ test('BleManager properly monitors characteristic value', async () => {
subscription.remove()
expect(listener).toHaveBeenCalledTimes(2)
expect(Native.BleModule.cancelTransaction).toBeCalledWith('x')
expect(Native.BleModule.monitorCharacteristicForDevice).toBeCalledWith('id', 'aaaa', 'bbbb', 'x', undefined)
expect(Native.BleModule.monitorCharacteristicForDevice).toBeCalledWith('id', 'aaaa', 'bbbb', 'x')
})

test('BleManager properly handles errors while monitoring characteristic values', async () => {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/Characteristic.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe("Test if Characteristic is properly calling BleManager's utility functi
test('monitor', async () => {
const listener = jest.fn()
await characteristic.monitor(listener, 'id')
expect(bleManager._monitorCharacteristic).toBeCalledWith('cId', listener, 'id', undefined)
expect(bleManager._monitorCharacteristic).toBeCalledWith('cId', listener, 'id')
})

test('readDescriptor', async () => {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe("Test if Device is properly calling BleManager's utility function:", ()
test('monitorCharacteristicForService', async () => {
const listener = jest.fn()
await device.monitorCharacteristicForService('aaaa', 'bbbb', listener, 'id')
expect(bleManager.monitorCharacteristicForDevice).toBeCalledWith('id', 'aaaa', 'bbbb', listener, 'id', undefined)
expect(bleManager.monitorCharacteristicForDevice).toBeCalledWith('id', 'aaaa', 'bbbb', listener, 'id')
})

test('readDescriptorForService', async () => {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/Service.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("Test if Service is properly calling BleManager's utility function:", (
test('monitorCharacteristic', async () => {
const listener = jest.fn()
await service.monitorCharacteristic('bbbb', listener, 'id')
expect(bleManager._monitorCharacteristicForService).toBeCalledWith('serviceId', 'bbbb', listener, 'id', undefined)
expect(bleManager._monitorCharacteristicForService).toBeCalledWith('serviceId', 'bbbb', listener, 'id')
})

test('readDescriptorForCharacteristic', async () => {
Expand Down
Loading