dotintent / react-native-ble-plx

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

[iOS] Scan - BleError: BluetoothLE is in unknown state #715

Closed ad-boschung closed 3 years ago

ad-boschung commented 4 years ago

Prerequisites

Expected Behavior

When the BleState is PoweredOn, I should be able to startScanDevices() without having BleError: BluetoothLE is in unknown state. I should be able to scan devices with and without "Remote Debug" enabled.

Current Behavior

When I start scanning my devices, I receive the BleError: BluetoothLE is in unknown state even if I waited that the BleManager State was in 'PoweredOn'. This behavior is only present when I enable the "Remote Debug" on iOS. It's working fine if I'm disable the "Remote Debug". It's really annoying because everybody is developing with the Remote Debug active I guess... Otherwise it's a bit complicated.

I don't see anything about this issue in the documentation. It's just written that we have to wait that the status is PoweredOnon iOS. And that's done... I found that it's not working with the "Remote Debug" active in this issue. I don't understand why there is no related issue or documentation about that...

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Run your app
  2. Activate Remote Debug
  3. Wait until State is PoweredOn
  4. Call startDevicesScan()
  5. See error...

Context

App.js


 startScan() {
    _deviceScanner.startDevicesScan(
      error => {
        console.error(error);
        _deviceScanner.stopDevicesScan();
      },
      device => {
        console.log(device);
      }
    );
  };

DeviceScanner.js

  /**
   * Wait until Bluetooth is ready. On iOS the BLE stack is not immediately ready,
   * we need to wait for the "PoweredOn" status.
   */
  async waitUntilBluetoothReady() {
    let {PoweredOn, PoweredOff, Unauthorized, Unsupported} = State;
    console.log('LIB : Wait until bluetooth ready...');
    return new Promise(async (resolve, reject) => {
      this._bleManager.onStateChange(state => {
        console.log('State changed : ', state);
        if (state === PoweredOn) {
          resolve(true);
        }
      });

     // Verify if the state is already poweredOn before the listener was created
      let crtState = await this._bleManager.state();
      console.log('Base state', crtState);
      if (crtState === PoweredOn) {
        resolve(true);
      } 
      else if (
        crtState === PoweredOff ||
        crtState === Unauthorized ||
        crtState === Unsupported
      ) {
        reject(new Error('Bluetooth is not available :', crtState));
      }
    });
  }

  /** 
   * Start device scanning only if the BleManager State is ready 
   */
  async startDevicesScan(
    onError: (error: Error) => void,
    onDeviceFound: (device: ConnectHubDevice) => void,
  ) {
    this.waitUntilBluetoothReady()
      .then(() => {
        console.log('LIB : Start scan...');
        const scanOptions = {
          allowDuplicates: false,
          scanMode: ScanMode.LowLatency,
        };
        this._bleManager.startDeviceScan(
          [SERVICE_UUID],
          scanOptions,
          (error, device) => {
            if (error) {
              onError(error);
            }
            if (device) {
              onDeviceFound(device);
            }
          },
        );
      })
      .catch(error => console.log(JSON.stringify(error));
  }
dariuszseweryn commented 4 years ago

Hi. Could you add logs on when the BleManager is being created? It looks like an issue with different lifecycles of your JS code and native parts.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

dan-lee commented 4 years ago

We see the same problem, it happens when I change anything outside React code. Only restarting the app fixes this. Do you know when and how different lifecycles of JS code and native parts can cause a problem?

purrsong-km commented 4 years ago

same here

purrsong-km commented 4 years ago

In my case, when the BleManager is being created and its log is

_activePromises: {} _activeSubscriptions: {} _errorCodesToMessagesMapping: {0: "Unknown error occurred. This is probably a bug! Check reason property.", 1: "BleManager was destroyed", 2: "Operation was cancelled", 3: "Operation timed out", 4: "Operation was rejected", 5: "Invalid UUIDs or IDs were passed: {internalMessage}", 100: "BluetoothLE is unsupported on this device", 101: "Device is not authorized to use BluetoothLE", 102: "BluetoothLE is powered off", 103: "BluetoothLE is in unknown state", 104: "BluetoothLE is resetting", 105: "Bluetooth state change failed", 200: "Device {deviceID} connection failed", 201: "Device {deviceID} was disconnected", 202: "RSSI read failed for device {deviceID}", 203: "Device {deviceID} is already connected", 204: "Device {deviceID} not found", 205: "Device {deviceID} is not connected", 206: "Device {deviceID} could not change MTU size", 300: "Services discovery failed for device {deviceID}", 301: "Included services discovery failed for device {deviceID} and service: {serviceUUID}", 302: "Service {serviceUUID} for device {deviceID} not found", 303: "Services not discovered for device {deviceID}", 400: "Characteristic discovery failed for device {deviceID} and service {serviceUUID}", 401: "Characteristic {characteristicUUID} write failed for device {deviceID} and service {serviceUUID}", 402: "Characteristic {characteristicUUID} read failed for device {deviceID} and service {serviceUUID}", 403: "Characteristic {characteristicUUID} notify change …d for device {deviceID} and service {serviceUUID}", 404: "Characteristic {characteristicUUID} not found", 405: "Characteristics not discovered for device {deviceID} and service {serviceUUID}", 406: "Cannot write to characteristic {characteristicUUID} with invalid data format: {internalMessage}", 500: "Descriptor {descriptorUUID} discovery failed for d…viceUUID} and characteristic {characteristicUUID}", 501: "Descriptor {descriptorUUID} write failed for devic…viceUUID} and characteristic {characteristicUUID}", 502: "Descriptor {descriptorUUID} read failed for device…viceUUID} and characteristic {characteristicUUID}", 503: "Descriptor {descriptorUUID} not found", 504: "Descriptors not discovered for device {deviceID}, …viceUUID} and characteristic {characteristicUUID}", 505: "Cannot write to descriptor {descriptorUUID} with invalid data format: {internalMessage}", 506: "Cannot write to descriptor {descriptorUUID}. It's …y iOS and therefore forbidden on Android as well.", 600: "Cannot start scanning operation", 601: "Location services are disabled"} _eventEmitter: NativeEventEmitter {_subscriber: EventSubscriptionVendor, _nativeModule: {…}} _uniqueId: 0

and when things went well log is

_activePromises: 9: ƒ (reason) proto: Object _activeSubscriptions: 8: {remove: ƒ} proto: Object _errorCodesToMessagesMapping: {0: "Unknown error occurred. This is probably a bug! Check reason property.", 1: "BleManager was destroyed", 2: "Operation was cancelled", 3: "Operation timed out", 4: "Operation was rejected", 5: "Invalid UUIDs or IDs were passed: {internalMessage}", 100: "BluetoothLE is unsupported on this device", 101: "Device is not authorized to use BluetoothLE", 102: "BluetoothLE is powered off", 103: "BluetoothLE is in unknown state", 104: "BluetoothLE is resetting", 105: "Bluetooth state change failed", 200: "Device {deviceID} connection failed", 201: "Device {deviceID} was disconnected", 202: "RSSI read failed for device {deviceID}", 203: "Device {deviceID} is already connected", 204: "Device {deviceID} not found", 205: "Device {deviceID} is not connected", 206: "Device {deviceID} could not change MTU size", 300: "Services discovery failed for device {deviceID}", 301: "Included services discovery failed for device {deviceID} and service: {serviceUUID}", 302: "Service {serviceUUID} for device {deviceID} not found", 303: "Services not discovered for device {deviceID}", 400: "Characteristic discovery failed for device {deviceID} and service {serviceUUID}", 401: "Characteristic {characteristicUUID} write failed for device {deviceID} and service {serviceUUID}", 402: "Characteristic {characteristicUUID} read failed for device {deviceID} and service {serviceUUID}", 403: "Characteristic {characteristicUUID} notify change …d for device {deviceID} and service {serviceUUID}", 404: "Characteristic {characteristicUUID} not found", 405: "Characteristics not discovered for device {deviceID} and service {serviceUUID}", 406: "Cannot write to characteristic {characteristicUUID} with invalid data format: {internalMessage}", 500: "Descriptor {descriptorUUID} discovery failed for d…viceUUID} and characteristic {characteristicUUID}", 501: "Descriptor {descriptorUUID} write failed for devic…viceUUID} and characteristic {characteristicUUID}", 502: "Descriptor {descriptorUUID} read failed for device…viceUUID} and characteristic {characteristicUUID}", 503: "Descriptor {descriptorUUID} not found", 504: "Descriptors not discovered for device {deviceID}, …viceUUID} and characteristic {characteristicUUID}", 505: "Cannot write to descriptor {descriptorUUID} with invalid data format: {internalMessage}", 506: "Cannot write to descriptor {descriptorUUID}. It's …y iOS and therefore forbidden on Android as well.", 600: "Cannot start scanning operation", 601: "Location services are disabled"} _eventEmitter: NativeEventEmitter {_subscriber: EventSubscriptionVendor, _nativeModule: {…}} _scanEventSubscription: null _uniqueId: 9 proto: Object

it seems the BleManager's _activePromises and _activeSubscriptions are different. I marked with bold text.

P.S. It occurs very frequently in iOS(higher than 13.3.1) not in Andorid.

purrsong-km commented 3 years ago

Is there any progress??

EzeRangel commented 3 years ago

This also happen when you're using functional components and/or Hooks. Even if you disable the remote debug, still shows the Unknown state Error.

piotrdubiel commented 3 years ago

Could you make a repository with reproduction of this issue? Main part missing in code above is how BleManager is created and how it's passed to the component.

VittoriDavide commented 3 years ago

I am also having this issue: BluetoothLE is in unknown state

in the Xcode console I can see also this error 2020-12-27 10:00:07.279967+0100 [19145:4875543] [CoreBluetooth] API MISUSE: <CBCentralManager: 0x2820e9180> has no restore identifier but the delegate implements the centralManager:willRestoreState: method. Restoring will not be supported 2020-12-27 10:00:07.280866+0100 [19145:4874888] [CoreBluetooth] XPC connection invalid

gregogalante commented 3 years ago

I'm getting exactly the same problem.

This is the log:

2020-12-29 17:43:54.156254+0100 MiPlus[670:31923] [CoreBluetooth] API MISUSE: <CBCentralManager: 0x2821b07e0> has no restore identifier but the delegate implements the centralManager:willRestoreState: method. Restoring will not be supported 2020-12-29 17:43:54.160394+0100 MiPlus[670:33450] [CoreBluetooth] XPC connection invalid

dariuszseweryn commented 3 years ago

It is important to keep only a single instance of BleManager. Readme was recently updated to stress this out.

dayaki commented 3 years ago

Am using only one single instance of BleManager and I still get the error

EDIT: I was using Hooks, problem solved for me now.

dariuszseweryn commented 3 years ago

Using Hooks does not mean that you use only a single instance of anything. You need to learn what each hook does and when it reloads its value.

gregogalante commented 3 years ago

My code was something like this:

constructor() {
  this.manager = new BleManager()
}

reset() {
  this.manager.destroy()
  this.manager = new BleManager()
}

connect() {
  this.reset()
  this.manager.scan()
}

In Android i need to reset the BLE manager because of some problems on re-connection with a Huawei Tablet. In IOS I'm getting the error "[CoreBluetooth] XPC connection invalid".

I resolved the bug in release mode with this edit:

// ...
connect() {
  if (Platform.os === 'android') this.reset()
  this.manager.scan()
}

However I still have the problem in debug mode with active debugger.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

priyasamyal commented 9 months ago

@ad-boschung Are you able to solve this issue? I am facing the same issue

mmp-star commented 1 month ago

When initializing BleManager, adding an arrow function is effective for me:

const [bleManager]=useSafeState()=>new BleManage() //Use the function initialization to ensure that only one instance is created