dotintent / react-native-ble-plx

React Native BLE library
Apache License 2.0
3.05k stars 513 forks source link

Bug Report #969

Open MaximeLozach opened 2 years ago

MaximeLozach commented 2 years ago

Expected Behavior

When app or device loose connection I should be hable to see it in device scan or if I don't see it, be able to disconnect to it.

Current Behavior

Sometimes, it looks like I loose connection. I don't see my device when performing startDeviceScan(). But I can't disconnect. Result of connectedDevices([serviceUUID]) is empty and cancelDeviceConnection(deviceId) return an error saying I'm not connected to device. My device don't change it's mac so I'm certain that my deviceId is correct.

The only way to get out of this situation I found is to shutdown bluetooth on my phone et put it back on. After that I'm able to see my device with startDeviceScan().

Steps to Reproduce

It's not something I can reproduce with precise steps but it goes on "disconnected" state when I don't do anything for several minute or sometimes when I reload with metro.

And I can only know I'm on this state by trying to scan or disconnect and it doesn't work.

Context

await this.getBleManager().cancelDeviceConnection(deviceID); => [BleError: Device CE:A5:1C:75:99:EE is not connected]

this.getBleManager().startDeviceScan(null, null, (error, device) => {console.log(device.id)}) => see all other device but mine

MaximeLozach commented 2 years ago

Going through all the issue I think my solution might be in implementing restoreStateIdentifier and restoreStateFunction when I create the BleManager. Because the issue seems to occure when the object get lost with metro reloading. But I can't find a proper example of implementation and for me the doc is not clear enough to understand how to set up the implementation. My question are :

MaximeLozach commented 2 years ago

Update:

I implemented this

stateFunction = (bleRestoredState) => {
    console.log(`[RESTORED STATE]`)
    console.log(bleRestoredState)
    if (bleRestoredState == null) {
        console.log("BleManager was constructed for the first time.")
    } else {
        console.log("BleManager was restored. Check `bleRestoredState.connectedPeripherals` property.")
        console.log(bleRestoredState.connectedPeripherals)
    }
}

getBleManager = () => {
    if (!this.bleManager) {
        console.log(`--- NEW BLE MANAGER ---`);
        this.bleManager = new BleManager({
            restoreStateIdentifier: 'LockManager-state-id',
            restoreStateFunction: this.stateFunction
        });
    }
    return this.bleManager;
};

but in fact on each reload, bleRestoredStateis null.

MaximeLozach commented 2 years ago

After continuing my research; It looks like the issue occurs on reload with metro. I lost the instance of BleManager and it's what stuck my app in connected but not recoverable state. Is there a way to save BleManager object in something like localstorage to keep the instance upon reload ? Or something I missed in the doc to make BleManager recover connection.

AkashWaghule commented 2 years ago

+1

tspiechaczek commented 1 year ago

I'm having the same issue.

It looks like BleManager is not persisting connected devices between Metro reloads. I need to disable and reenable Bluetooth adapter to be able to scan for the same device again.

kavindadilshan commented 1 year ago

any updates?

viaesys commented 8 months ago

+1

flexbox commented 4 months ago

@MaximeLozach I am late to the party for this ticket 😅 but have you find a way to keep the bluetooth connection between reloads?

I just landed exactly on the same scenario as yours:

  1. successfully paired device
  2. BLESInstance is connected
  3. I loose the connection because i raise an error during programming.

I want to quickly reconnect, without pairing again the device.

From my understanding we can use BleManagerOptions

/**
 * Options for the BleManager. use it for debugging and restoring the state.
 */
const options: BleManagerOptions = {
  restoreStateIdentifier: "BleInTheBackground",
  restoreStateFunction: (restoredState: BleRestoredState | null) => {
    if (restoredState == null) {
      logger.log("🆕 ~ BleManager was constructed for the first time.");
    } else {
      logger.log(
        "💾 ~ BleManager BleManager was restored.",
        restoredState.connectedPeripherals
      );
    }
  }
};

when we create new instances with

new BleManager(options)

But I have no idea on how it use restoreStateFunction.

intent-kacper-cyranowski commented 3 months ago

Hi everyone On version 3.2.1 we have added support for invalidating native module on android. Can someone confirm that it solves this issue?

helloworld-Andrew commented 1 month ago

Hi guys, I found a function from the BleManager.destroy(). You can call it when your root view unmounts. It will auto-disconnect the current device when the application reloads. Hope this function works for you guys.