pauldemarco / flutter_blue

Bluetooth plugin for Flutter
BSD 3-Clause "New" or "Revised" License
2.36k stars 1.23k forks source link

Scan fail on iOS when device changes exposed services (on firmware update) #493

Open diso73 opened 4 years ago

diso73 commented 4 years ago

Hi, I'm trying to upload the firmware to the BLE device. To do this I must connect to the device while in "normal" mode (firmware running as usual) and issue a command that reboot the device and switch it into a "bootloader" mode, that is ready to receive the new firmware.

After the reboot, the device changes it's exposed services (and the name) but the device Id remains the same.

When I start a scan for the device when in "bootloader" mode, the scan returns the device (by the truth, with the old name, not the default 'BLE DFU Device' it assumes when in bootloader mode), but without list the newly exposed "Bootloader update" service (visible only when in 'bootloader' mode).

It seems that something is cached or not refreshed. The device Id is the same, ok, but services and name changes!

This happens only with iOS, the same code runs ok in Android. The chip manufacturer's app runs ok listing the correct name and listing all the services across mode-switch. (Sources available at https://www.cypress.com/documentation/software-and-drivers/cysmart-mobile-app).

Could you please help me to address this issue?

Thank you

thachnb85 commented 4 years ago

You can simple ask user to go to Settings > Bluetooth , switch it Off, then On again. Now you can see the device with the new id.

boskokg commented 4 years ago

I think that bluetooth reset will not help in this plugin. Scanned devices are cached in the the plugin, and not cleared after the bluetooth reset. I am reproducing this issue in the production now, and only application restart helps... @pauldemarco do you have any idea how we can can fix this issue?

pauldemarco commented 4 years ago

The only way to clear this cache is for an app restart on iOS. The typical workaround for this is to increment the device address after you update the peripheral. There’s a bunch of information out there on how to do this properly, for instance: https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library/issues/178

I don’t believe there is anything we can do at the plugin level, but I’ll leave this open for a bit if anyone has some thoughts.

pauldemarco commented 4 years ago

I noticed today I was able to clear the iOS cache by toggling airplane mode and Bluetooth adapter. There may be something we can do here.

For starters, I want to make sure flutter_blue is handling its own cache properly when Bluetooth is disabled. Does it make sense to clear everything when Bluetooth is turned off? Does there exist any future platform that might be able to connect to devices that were found before the reset?

Leaving this open for further investigation.

Kleak commented 3 years ago

I have the same problem after doing something with a device the services exposed are changing but when i scan it's not updated.

could we add the BluetoothGatt.refresh method to the plugin ?

  private boolean refreshDeviceCache(final BluetoothGatt gatt) {
    if (gatt == null)
      return false;
    /*
     * There is a refresh() method in BluetoothGatt class but for now it's hidden. We will call it using reflections.
     */
    try {
      final Method refresh = gatt.getClass().getMethod("refresh");
      if (refresh != null) {
        return (Boolean) refresh.invoke(gatt);
      }
    } catch (final Exception e) {
      log(LogContract.Log.Level.ERROR, "An exception occurred while refreshing device " + e.getMessage());
    }
    return false;
  }

something like that ? since this method is hidden it's probably not the best answer to the problem ^^