dotintent / react-native-ble-plx

React Native BLE library
Apache License 2.0
3.08k stars 515 forks source link

🐛 IOS\Android disconnecting from bluetooth device after connecting if we don't write characteristics after 30 seconds. #1219

Open vipien opened 5 months ago

vipien commented 5 months ago

Prerequisites

Expected Behavior

We connect to the device and we remain connected even if we do not print a label.

Current Behavior

We connect to the device, in this case a Zebra Printer, and after some seconds (30) it automatically disconnect. We do not receive any error on the onDisconnected listener. If we connect and print (write characteristic) before disconnecting, it remains connected. We do not let the phone turn off the screen.

Library version

3.2.0

Device

Iphone 13 (17.5.1) Google Pixel

Environment info

System:
  OS: macOS 14.5
  CPU: (8) arm64 Apple M1 Pro
  Memory: 57.53 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 20.13.1
    path: ~/.nvm/versions/node/v20.13.1/bin/node
  Yarn:
    version: 1.22.18
    path: /usr/local/bin/yarn
  npm:
    version: 10.5.2
    path: ~/.nvm/versions/node/v20.13.1/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.15.2
    path: /usr/local/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.5
      - iOS 17.5
      - macOS 14.5
      - tvOS 17.5
      - visionOS 1.2
      - watchOS 10.5
  Android SDK: Not Found
IDEs:
  Android Studio: 2023.1 AI-231.9392.1.2311.11076708
  Xcode:
    version: 15.4/15F31d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.1
    wanted: 0.74.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

info React Native v0.74.2 is now available (your project is running on v0.74.1).
info Changelog: https://github.com/facebook/react-native/releases/tag/v0.74.2
info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.74.1
info For more info, check out "https://reactnative.dev/docs/upgrading?os=macos".

Steps to reproduce

  1. Scan
  2. Connect to device
  3. Discover all services and characteristics
  4. Get services
  5. Wait around 15~ seconds and the device will disconnect.

Formatted code sample or link to a repository

await BLEManager.connectToDevice(device.id);

// Not used, but it's necessary to discover services and characteristics
await device.discoverAllServicesAndCharacteristics();
await device.services();

const characteristics = await device.characteristicsForService(
  ZEBRA_PRINT_SERVICE_UUID
);

const characteristic = characteristics.find(
  (char) => char.uuid === ZEBRA_PRINT_CHARACTERISTIC_UUID
);

if (!characteristic) {
  const characteristicsNotFoundError = new Error(
    "Characteristic not found"
  );
  crashalytics().recordError(characteristicsNotFoundError);
  throw characteristicsNotFoundError;
}

device.onDisconnected((error, device) => {
  if (error) {
    console.error("Error disconnecting", error);
    crashalytics().recordError(error);
  }
})

Relevant log output

This is what we receive on the onDisconnected listener:

error: null 
device: {"_manager": {"_activePromises": {}, "_activeSubscriptions": {"42": [Object]}, "_errorCodesToMessagesMapping": {"0": "Unknown error occurred. This is probably a bug! Check reason property.", "1": "BleManager was destroyed", "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", "2": "Operation was cancelled", "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", "3": "Operation timed out", "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}", "4": "Operation was rejected", "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 failed 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}", "5": "Invalid UUIDs or IDs were passed: {internalMessage}", "500": "Descriptor {descriptorUUID} discovery failed for device {deviceID}, service {serviceUUID} and characteristic {characteristicUUID}", "501": "Descriptor {descriptorUUID} write failed for device {deviceID}, service {serviceUUID} and characteristic {characteristicUUID}", "502": "Descriptor {descriptorUUID} read failed for device {deviceID}, service {serviceUUID} and characteristic {characteristicUUID}", "503": "Descriptor {descriptorUUID} not found", "504": "Descriptors not discovered for device {deviceID}, service {serviceUUID} and characteristic {characteristicUUID}", "505": "Cannot write to descriptor {descriptorUUID} with invalid data format: {internalMessage}", "506": "Cannot write to descriptor {descriptorUUID}. It's not allowed by iOS and therefore forbidden on Android as well.", "600": "Cannot start scanning operation", "601": "Location services are disabled"}, "_eventEmitter": {"_nativeModule": [Object]}, "_scanEventSubscription": null, "_uniqueId": 44, "destroy": [Function anonymous], "onStateChange": [Function anonymous], "state": [Function anonymous], "stopDeviceScan": [Function anonymous]}, "id": "12A14AAC-0693-2DBB-B72D-FD5ED35C7A53", "isConnectable": null, "localName": null, "manufacturerData": null, "mtu": 23, "name": "D2J205207340", "overflowServiceUUIDs": null, "rawScanRecord": null, "rssi": null, "serviceData": null, "serviceUUIDs": null, "solicitedServiceUUIDs": null, "txPowerLevel": null}

Additional information

No response

intent-kacper-cyranowski commented 5 months ago

Hello @vipien The problem you mention seems to be related to #1197 . Unfortunately, I have a problem with reproducing it because it does not occur on any device I have checked. Could you try to connect to this printer using our example app and confirm that the problem still occurs? Here is the branch where we try to reproduce this issue https://github.com/dotintent/react-native-ble-plx/blob/fix/1197_device_automatically_disconnecting/example/src/screens/MainStack/DisconnectBeforeWrite/DisconnectBeforeWrite.tsx Have you tried connecting to the device using other applications, e.g. nRF Connect? It is possible that the device has a disconnection mechanism on its side when there is no activity after connect.

vipien commented 4 months ago

Hi! Thanks for taking the time to check it.

We tried to run the example app and we could not make it work. Is there a guide that we can follow?

We have also tested it better. We know that is exactly after 30 seconds. It also happens in the Google Pixel we have for testing, not only in iPhones.

The behavior is the same, we search, connect, and keep the app alive. If we do not print in the next 30 seconds it disconnects.

We also know this is not a printer problem because we can connect with another app and it remains connected without printing.

I hope this information is useful for you to find out why. For now we added a wait with 3 seconds after the connection is made and we print a "Connected to printer" label, but we don't like this solution.

intent-kacper-cyranowski commented 4 months ago

What problems do you have with example app? I'm aware of one issue with iOS and to solve it you would have to remove .xcode.env.local, fix will be added in next patch. Changing the time span of waiting without performing any operations didn't yield results for me - connection is still open after 40 seconds, tested on iOS What is another app? Can you confirm that it's not performing any operations to sustain the connection?

First of all I would like to confirm that it's not the printer that is closing connection. To do so I would need you to adjust our example app disconnectBeforeWrite to work with your printer, or test your app agains different device to confirm that connection also will be dropped. Preferably it would be both as one does not confirm the other.

Additionally system level logs from xCode/Logcat could provide more insight. You can collect logs after using setLogLevel with LogLevel.Verbose. You can reduce the information clutter by filtering out logs for example for Logcat it could be package:mine (tag:BluetoothGatt | tag:ReactNativeJS | RxBle)

intent-kacper-cyranowski commented 4 months ago

Hi @vipien Did you manage to fix the issue? If not, can I help in any way?