Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with [BleError: Operation was cancelled] on iOS 17 #1230

Open
4 tasks done
HwangJungeon opened this issue Aug 4, 2024 · 15 comments
Open
4 tasks done

Issue with [BleError: Operation was cancelled] on iOS 17 #1230

HwangJungeon opened this issue Aug 4, 2024 · 15 comments
Labels

Comments

@HwangJungeon
Copy link

Prerequisites

  • I checked the documentation and FAQ without finding a solution
  • I checked to make sure that this issue has not already been filed
  • I'm sure that question is related to the library itself and not Bluetooth Low Energy or Classic in general. If that so, please post your question on StackOverflow.
  • I'm running the latest version

Question

Hello,

I am encountering an issue with the [BleError: Operation was cancelled] error on iOS 17. This problem does not occur when testing on AOS, but it started appearing on iOS after a period of smooth operation. The issue persists consistently.

I have reviewed and attempted solutions suggested in previous issues, such as Connection Error 2 "Operation was cancelled" on IOS16 #1080. I tried using device.cancelConnection() before device.connect() and modified my code to ensure that new BleManager() is called only once by implementing a singleton pattern. Despite these efforts, the problem remains unresolved.

The most perplexing aspect is that the connection works fine on iOS initially, but the error reappears the next day upon retrying.

Additionally, I have verified iOS permissions, cleaned the iOS build folder, and retried the process. I am currently using the latest version of react-native-ble-plx (3.2.1).

Environment:

  • iOS Version: 17
  • react-native-ble-plx Version: 3.2.1

Any assistance or insights into resolving this issue would be greatly appreciated.

Thank you.

Question related code

No response

@shanez
Copy link

shanez commented Aug 21, 2024

@HwangJungeon What iOS minor version are you on?

@HwangJungeon
Copy link
Author

HwangJungeon commented Aug 22, 2024

@HwangJungeon What iOS minor version are you on?
@shanez I used iOS version 17.5.1 (21F90)

@ebadia
Copy link

ebadia commented Aug 23, 2024

Same here using 3.2.1 on:

  • iOS 17.5.1
  • iOS 16.7.8

Tried several "connect/disconnect" combinations all with the same result:
'ERROR', [BleError: Operation was cancelled]

Help appreciated too. Thanks!!!

@HwangJungeon
Copy link
Author

@ebadia
In my case, I tried reinstalling the node module, which helped a bit, but still intermittently throwing the error 'ERROR', [BleError: Operation was canceled]

@HwangJungeon HwangJungeon closed this as not planned Won't fix, can't repro, duplicate, stale Aug 24, 2024
@HwangJungeon HwangJungeon reopened this Aug 24, 2024
@ebadia
Copy link

ebadia commented Aug 25, 2024

@ebadia In my case, I tried reinstalling the node module, which helped a bit, but still intermittently throwing the error 'ERROR', [BleError: Operation was canceled]

I deleted node_modules folder, install them again, but the error persists. Thanks for your response!

@HwangJungeon
Copy link
Author

@ebadia In my case, I tried reinstalling the node module, which helped a bit, but still intermittently throwing the error 'ERROR', [BleError: Operation was canceled]

I deleted node_modules folder, install them again, but the error persists. Thanks for your response!

It still happens to me too... I'll continue to try different things to fix the error, and if I find a good solution, I'll share it!

@ebadia
Copy link

ebadia commented Aug 25, 2024

@ebadia In my case, I tried reinstalling the node module, which helped a bit, but still intermittently throwing the error 'ERROR', [BleError: Operation was canceled]

I deleted node_modules folder, install them again, but the error persists. Thanks for your response!

It still happens to me too... I'll continue to try different things to fix the error, and if I find a good solution, I'll share it!

Thanks, I will do the same

@intent-kacper-cyranowski
Copy link
Collaborator

Hi @HwangJungeon @ebadia
Could you provide repro of your issue and collect logs?

@ebadia
Copy link

ebadia commented Aug 30, 2024

This is the code I use to identify and connect to the BLE device (a weight scale)

            if (device.name === "Chipsea-BLE") {
              console.log("IDENTIFICADOR", device.name);
              console.log("IM CONNECTED", await device.isConnected());

              ble.stopDeviceScan();
              if (!await device.isConnected()) {
                try {
                  await device.connect();

                  console.log("CONNECTED", device.id);

                } catch (e) {
                  console.log("ERROR CONN", e);
                }
              }

This is the log from this piece of code:

[RxBLEKit|VERB|12:05:52.175]: CentralManager(10763401600) didDiscover(peripheral: Peripheral(uuid: 1ECEA624-9BC7-60C4-74B4-E09FA61E3456, name: Optional("Chipsea-BLE")),
rssi: -60)
2024-08-30 13:05:52.176105+0100 pronokalPre[38603:3770084] [javascript] 'IDENTIFICADOR', 'Chipsea-BLE'
2024-08-30 13:05:52.178016+0100 pronokalPre[38603:3770084] [javascript] 'IDENTIFICADOR', 'Chipsea-BLE'
[RxBLEKit|VERB|12:05:52.178]: CentralManager(10763401600) didDiscover(peripheral: Peripheral(uuid: 3E3349C0-05D8-8F5C-E6CF-9DA14F1D790C, name: nil),
rssi: -73)
2024-08-30 13:05:52.179856+0100 pronokalPre[38603:3770084] [javascript] 'IM CONNECTED', false
[RxBLEKit|VERB|12:05:52.180]: CentralManager(10763401600) didDiscover(peripheral: Peripheral(uuid: 3E3349C0-05D8-8F5C-E6CF-9DA14F1D790C, name: nil),
rssi: -73)
[RxBLEKit|DEBG|12:05:52.182]: CentralManager(10763401600) stopScan()
2024-08-30 13:05:52.183974+0100 pronokalPre[38603:3770084] [javascript] 'IM CONNECTED', false
[RxBLEKit|DEBG|12:05:52.186]: CentralManager(10763401600) retrievePeripherals(
withIdentifiers: [1ECEA624-9BC7-60C4-74B4-E09FA61E3456])
[RxBLEKit|DEBG|12:05:52.190]: CentralManager(10763401600) connect(
peripheral: Peripheral(uuid: 1ECEA624-9BC7-60C4-74B4-E09FA61E3456, name: Optional("Chipsea-BLE")),
options: nil)
[RxBLEKit|DEBG|12:05:52.191]: CentralManager(10763401600) retrievePeripherals(
withIdentifiers: [1ECEA624-9BC7-60C4-74B4-E09FA61E3456])
[RxBLEKit|DEBG|12:05:52.191]: CentralManager(10763401600) connect(
peripheral: Peripheral(uuid: 1ECEA624-9BC7-60C4-74B4-E09FA61E3456, name: Optional("Chipsea-BLE")),
options: nil)
[RxBLEKit|DEBG|12:05:52.192]: CentralManager(10763401600) cancelPeripheralConnection(
peripheral: Peripheral(uuid: 1ECEA624-9BC7-60C4-74B4-E09FA61E3456, name: Optional("Chipsea-BLE")))
[RxBLEKit|DEBG|12:05:52.226]: CentralManager(10763401600) didDisconnect(from: Peripheral(uuid: 1ECEA624-9BC7-60C4-74B4-E09FA61E3456, name: Optional("Chipsea-BLE")),
error: nil)
2024-08-30 13:05:52.229912+0100 pronokalPre[38603:3770084] [javascript] 'ERROR CONN', [BleError: Operation was cancelled]
[RxBLEKit|DEBG|12:06:05.973]: CentralManager(10763401600) cancelPeripheralConnection(
peripheral: Peripheral(uuid: 1ECEA624-9BC7-60C4-74B4-E09FA61E3456, name: Optional("Chipsea-BLE")))
2024-08-30 13:06:06.010458+0100 pronokalPre[38603:3770081] [CoreBluetooth] XPC connection invalid

Hope it helps you!

@HwangJungeon
Copy link
Author

@intent-kacper-cyranowski

I apologize for the delayed response to your comment. As the issue persists, I've attempted the following approach, which seems to work without any problems:

if (error instanceof Error && error.message.includes('Operation was cancelled')) {
    this.manager.destroy();
    this.manager = new BleManager();
    return this.connectToDevice(deviceId);
}

This method catches the "Operation was cancelled" error, destroys the existing instance, creates a new one, and then attempts to reconnect to the device.

Do you think this approach is acceptable to use?

@ebadia
Copy link

ebadia commented Sep 9, 2024

@intent-kacper-cyranowski

I apologize for the delayed response to your comment. As the issue persists, I've attempted the following approach, which seems to work without any problems:

if (error instanceof Error && error.message.includes('Operation was cancelled')) {
    this.manager.destroy();
    this.manager = new BleManager();
    return this.connectToDevice(deviceId);
}

This method catches the "Operation was cancelled" error, destroys the existing instance, creates a new one, and then attempts to reconnect to the device.

Do you think this approach is acceptable to use?

Still have issues, will continue trying different approaches. Thanks!

@zachTrio
Copy link

@intent-kacper-cyranowski
I apologize for the delayed response to your comment. As the issue persists, I've attempted the following approach, which seems to work without any problems:

if (error instanceof Error && error.message.includes('Operation was cancelled')) {
    this.manager.destroy();
    this.manager = new BleManager();
    return this.connectToDevice(deviceId);
}

This method catches the "Operation was cancelled" error, destroys the existing instance, creates a new one, and then attempts to reconnect to the device.
Do you think this approach is acceptable to use?

Still have issues, will continue trying different approaches. Thanks!

Have you settled on a new approach? Running into the same error.

@HwangJungeon
Copy link
Author

@zachTrio The method I showed is simple, but still works well. I'm still using it and it's working fine on iOS 18.

@zachTrio
Copy link

@HwangJungeon I'll give it a go.

Though, I feel like I was trying to still track down where this error was throwing when I commented on this issue.

The stack trace was fairly useless from what I remember and I think just about everything can throw the 'Operation was cancelled'

What function/s are you catching here.

@Akuma-U1
Copy link

Hi, I encountered this error as well, and fixed it. The error comes from iOS scanning very quickly in the startDeviceScan function. The listener callback function activates multiple times for the same device id, causing the device to cancel all of the connections.

To fix this, you can do the following:

  1. Explicitly tell the BLEManger to not catch duplicates in the options of the startDeviceScan function, as follows
bleManager.startDeviceScan(
        [SERVICE_UUID_LIST],
        {
          allowDuplicates: false, // <----- This line
          callbackType: ScanCallbackType.AllMatches,
          scanMode: ScanMode.LowLatency
        },
        deviceFoundFunction
)
  1. Inside of the listener function you can check wether or not the current device you are trying to connect to, is already trying to get a connection. I did this by calling startDeviceScan() in a wrapper function, then having a variable called currentDeviceId at the top level of the function, then setting the listener function as an arrow function so that it can have currentDeviceId in its scope. The implementation looks something like this
function startDeviceScanWrapper(deviceName:string){
   let currentDeviceId = ""; // Set variable that keeps track of what we are busy with
   bleManager.startDeviceScan( [SERVICE_UUID_LIST],
        {
          allowDuplicates: false, 
          callbackType: ScanCallbackType.AllMatches,
          scanMode: ScanMode.LowLatency
        },
        async (error, device) => { // <------ Start of device scan callback listener
          if (error) {
            await logger(`🛑: Error scanning for devices: ${error}`);
            return;
          }

          // Check if we got a device, and if it's the correct one
          if (
            device &&
            device.isConnectable &&
            (device.name === deviceName || device.localName === deviceName)
          ) {
            const name = device.name ?? device.localName;
            await logger(`✅: Found device: ${name}`);
            if (currentDeviceId === device.id) {
              await logger(
                "🛑: Multiple connection attempts to a single device. Dropping this attempt."
              );
              return;
            } else {
              currentDeviceId = device.id;
            }
            // ..... Rest of your code after this to handle connecting to a device
            // Something like device.connect(......)
       }
}

Hope this helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants