React-native-ble-plx: [iOS] Scan - BleError: BluetoothLE is in unknown state

Created on 16 Jul 2020  路  14Comments  路  Source: Polidea/react-native-ble-plx

Prerequisites

  • [x] I am running the latest version
  • [x] I checked the documentation and found no answer
  • [x] I checked to make sure that this issue has not already been filed

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

  • Library version: 2.0.1
  • Platform: iOS.
  • JS logs:
DeviceScanner.js:17 LIB : Wait until bluetooth ready...
DeviceScanner.js:28 Base state PoweredOn
DeviceScanner.js:57 LIB : Start scan...
DeviceScanner.js:70 Scan error :  {"message":"BluetoothLE is in unknown state","errorCode":103,"attErrorCode":null,"iosErrorCode":null,"androidErrorCode":null,"reason":null,"name":"BleError"}
DeviceScanner.js:85 LIB : Scan stopped
DeviceScanner.js:22 State change :  PoweredOn
  • Formatted code sample or link to a repository:

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));
  }
bug

All 14 comments

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.

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.

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?

same here

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 鈥 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鈥iceUUID} and characteristic {characteristicUUID}", 501: "Descriptor {descriptorUUID} write failed for devic鈥iceUUID} and characteristic {characteristicUUID}", 502: "Descriptor {descriptorUUID} read failed for device鈥iceUUID} and characteristic {characteristicUUID}", 503: "Descriptor {descriptorUUID} not found", 504: "Descriptors not discovered for device {deviceID}, 鈥iceUUID} and characteristic {characteristicUUID}", 505: "Cannot write to descriptor {descriptorUUID} with invalid data format: {internalMessage}", 506: "Cannot write to descriptor {descriptorUUID}. It's 鈥 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 鈥 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鈥iceUUID} and characteristic {characteristicUUID}", 501: "Descriptor {descriptorUUID} write failed for devic鈥iceUUID} and characteristic {characteristicUUID}", 502: "Descriptor {descriptorUUID} read failed for device鈥iceUUID} and characteristic {characteristicUUID}", 503: "Descriptor {descriptorUUID} not found", 504: "Descriptors not discovered for device {deviceID}, 鈥iceUUID} and characteristic {characteristicUUID}", 505: "Cannot write to descriptor {descriptorUUID} with invalid data format: {internalMessage}", 506: "Cannot write to descriptor {descriptorUUID}. It's 鈥 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.

Is there any progress??

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.

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.

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: 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

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: 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

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

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

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

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.

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kevinmeyvaert picture kevinmeyvaert  路  4Comments

SlavaInstinctools picture SlavaInstinctools  路  4Comments

samthui picture samthui  路  4Comments

alfacommunication-alessandro picture alfacommunication-alessandro  路  4Comments

brycejacobs picture brycejacobs  路  5Comments