Flutter library that handles BLE operations for multiple devices.

Overview

Flutter reactive BLE library

flutter_reactive_ble version

Flutter library that handles BLE operations for multiple devices.

Usage

The reactive BLE lib supports the following:

  • BLE device discovery
  • Observe host device BLE status
  • Establishing a BLE connection
  • Maintaining connection status of multiple BLE devices
  • Discover services(will be implicit)
  • Read / write a characteristic
  • Subscribe to a characteristic
  • Clear GATT cache
  • Negotiate MTU size

Initialization

Initializing the library should be done the following:

final flutterReactiveBle = FlutterReactiveBle();

Device discovery

Discovering BLE devices should be done like this:

flutterReactiveBle.scanForDevices(withServices: [serviceId], scanMode: ScanMode.lowLatency).listen((device) {
      //code for handling results
    }, onError: () {
      //code for handling error
    });
  

The withServices parameter specifies the advertised service IDs to look for. If an empty list is passed, all the advertising devices will be reported. The parameter scanMode is only used on Android and follows the conventions described on ScanSettings Android reference page. If scanMode is omitted the balanced scan mode will be used.

Observe host device BLE status

Use statusStream to retrieve updates about the BLE status of the host device (the device running the app) . This stream can be used in order to determine if the BLE is turned on, on the device or if the required permissions are granted. Example usage:

_ble.statusStream.listen((status) {
  //code for handling status update
});

Use _ble.status to get the current status of the host device.

Establishing connection

To interact with a device you first need to establish a connection:

flutterReactiveBle.connectToDevice(
      id: foundDeviceId,
      servicesWithCharacteristicsToDiscover: {serviceId: [char1, char2]},
      connectionTimeout: const Duration(seconds: 2),
    ).listen((connectionState) {
      // Handle connection state updates
    }, onError: (Object error) {
      // Handle a possible error
    });

For the required id parameter use a device ID retrieved through device discovery. On iOS the device ID is a UUID and on Android it is a MAC address (which may also be randomized, depending on the Android version). Supplying a map with service and characteristic IDs you want to discover may speed up the connection on iOS (otherwise all services and characteristics will be discovered). You can specify a connectionTimeout when the client will provide an error in case the connection cannot be established within the specified time.

There are numerous issues on the Android BLE stack that leave it hanging when you try to connect to a device that is not in range. To work around this issue use the method connectToAdvertisingDevice to first scan for the device and only if it is found connect to it.

flutterReactiveBle.connectToAdvertisingDevice(
    id: foundDeviceId,
    withServices: [serviceUuid],
    prescanDuration: const Duration(seconds: 5),
    servicesWithCharacteristicsToDiscover: {serviceId: [char1, char2]},
    connectionTimeout: const Duration(seconds:  2),
  ).listen((connectionState) {
    // Handle connection state updates
  }, onError: (dynamic error) {
    // Handle a possible error
  });

Besides the normal connection parameters that are described above this function also has 2 additional required parameters: withServices and prescanDuration. PreScanDuration is the amount of time the ble stack will scan for the device before it attempts to connect (if the device is found)

Read / write characteristics

Read characteristic

final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: foundDeviceId);
final response = await flutterReactiveBle.readCharacteristic(characteristic);

Write with response

Write a value to characteristic and await the response. The "response" in "write characteristic with response" means "an acknowledgement of reception". The write can either be acknowledged (success) or failed (an exception is thrown), thus the return type is void and there is nothing to print (though you can print("Write successful") and in a catch-clause print("Write failed: $e")).

BLE does not provide a request-response mechanism like you may know from HTTP out of the box. If you need to perform request-response calls, you will need to implement a custom mechanism on top of the basic BLE functionality. A typical approach is to implement a "control point": a characteristic that is writable and delivers notifications or indications, so that a request is written to it and a response is delivered back as a notification or an indication.

final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: foundDeviceId); 
await flutterReactiveBle.writeCharacteristicWithResponse(characteristic, value: [0x00]);

Write without response

Use this operation if you want to execute multiple consecutive write operations in a small timeframe (e.g uploading firmware to device) or if the device does not provide a response. This is performance wise the fastest way of writing a value but there's a chance that the BLE device cannot handle that many consecutive writes in a row, so do a writeWithResponse once in a while.

final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: foundDeviceId);
flutterReactiveBle.writeCharacteristicWithoutResponse(characteristic, value: [0x00]);

Subscribe to characteristic

Instead of periodically reading the characteristic you can also listen to the notifications (in case the specific service supports it) in case the value changes.

final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: foundDeviceId);
   flutterReactiveBle.subscribeToCharacteristic(characteristic).listen((data) {
      // code to handle incoming data
    }, onError: (dynamic error) {
      // code to handle errors
    });

Negotiate MTU size

You can increase or decrease the MTU size to reach a higher throughput. This operation will return the actual negotiated MTU size, but it is no guarantee that the requested size will be successfully negotiated. iOS has a default MTU size which cannot be negotiated, however you can still use this operation to get the current MTU.

final mtu = await flutterReactiveBle.requestMtu(deviceId: foundDeviceId, mtu: 250);

Android specific operations

The following operations will only have effect for Android and are not supported by iOS. When using these operations on iOS the library will throw an UnSupportedOperationException.

Request connection priority

On Android you can send a connection priority update to the BLE device. The parameter priority is an enum that uses the same spec as the BluetoothGatt Android spec. Using highPerformance will increase battery usage but will speed up GATT operations. Be cautious when setting the priority when communicating with multiple devices because if you set highperformance for all devices the effect of increasing the priority will be lower.

await flutterReactiveBle.requestConnectionPriority(deviceId: foundDeviceId, priority:  ConnectionPriority.highPerformance);

Clear GATT cache

The Android OS maintains a table per device of the discovered service in cache. Sometimes it happens that after a firmware update a new service is introduced but the cache is not updated. To invalidate the cache you can use the cleargattCache operation.

This is a hidden BLE operation and should be used with extreme caution since this operation is on the greylist.

await flutterReactiveBle.clearGattCache(foundDeviceId);

FAQ

How to handle the BLE undeliverable exception

On Android side we use the RxAndroidBle library of Polidea. After migration towards RxJava 2 some of the errors are not routed properly to their listeners and thus this will result in a BLE Undeliverable Exception. The root cause lies in the threading of the Android OS. As workaround RxJava has a hook where you can set the global errorhandler. For more info see RxJava docs .

A default workaround implementation in the Flutter app (needs to be in the Java / Kotlin part e.g. mainactivity) is shown below. For an example (in Java) see Polidea RxAndroidBle sample.

BleException is coming from Polidea RxAndroidBle, so make sure your application declares the following depedency: implementation "com.polidea.rxandroidble2:rxandroidble:1.11.1"

RxJavaPlugins.setErrorHandler { throwable ->
  if (throwable is UndeliverableException && throwable.cause is BleException) {
    return@setErrorHandler // ignore BleExceptions since we do not have subscriber
  }
  else {
    throw throwable
  }
}

Which permissions are needed?

Android

For android the library uses the following permissions:

  • ACCESS_FINE_LOCATION : this permission is needed because old Nexus devices need location services in order to provide reliable scan results
  • BLUETOOTH : allows apps to connect to a paired bluetooth device
  • BLUETOOTH_ADMIN: allows apps to discover and pair bluetooth devices

These permissions are already added in the manifest of the this library and thus should automatically merge into the manifest of your app. It is not needed to add the permissions in your manifest.

iOS

For iOS it is required you add the following entries to the Info.plist file of your app. It is not allowed to access Core BLuetooth without this. See our example app on how to implement this. For more indepth details: Blog post on iOS bluetooth permissions

iOS13 and higher

  • NSBluetoothAlwaysUsageDescription

iOS12 and lower

  • NSBluetoothPeripheralUsageDescription

How to adjust ProGuard (Android)

In case you are using ProGuard add the following snippet to your proguard-rules.pro file:

-keep class com.signify.hue.** { *; }

This will prevent issues like #131 .

Unofficial example apps

Example implementation UART over BLE:link

Comments
  • Read characteristics on iOS is not working

    Read characteristics on iOS is not working

    Describe the bug When a device connection is established, characteristics cannot be read on iOS, whereas on Android it works without any problem. Following error is printed:

    To Reproduce Steps to reproduce the behavior:

    1. Connect to one device using connectTo()
    2. Subscribe to a non-protected characteristic
    3. Observe a failure with following exception

    Error unsubscribing from notifications: PlatformException(flutter_reactive_ble.Central.(unknown context at $103218a20).Failure:1, The operation couldn’t be completed. (flutter_reactive_ble.Central.(unknown context at $103218a20).Failure error 1.), {})

        _connectedDeviceStream.where((device) => device.connectionState == DeviceConnectionState.connected).listen((onData) async {
          var chars = _ble.subscribeToCharacteristic(
            QualifiedCharacteristic(characteristicId: _charUuid, serviceId: _serviceUuid, deviceId: deviceId),
          );
          var listOfChars = await chars.toList();
          print('chars ${listOfChars.runtimeType} $listOfChars');
          _values.add(listOfChars);
        });
    

    Tablet

    • Device: iPad (7th generation)
    • OS: iOS 13.3.1
    opened by bulenthacioglu 31
  • Disconnect already connected Device after App restart

    Disconnect already connected Device after App restart

    in advance, thanks for your great job !

    i have a question...

    ■ Scenario 0
    1. connect to some device
    2. disconnect above device
    -----> doing well
    
    ■ Scenario 1
    1. connect to some device
    2. terminate app
    3. restart app
    -----> we can find connected device by
    -----> listening connectedDeviceStream
    

    here is the problem or my ignorance

    How can i disconnect device what found by connectedDeviceStream
    not from manually connectToDevice nor connectToAdvertisingDevice ?
    
    i already know canceling stream from connectToDevice
    or connectToAdvertisingDevice take disconnection
    
    but, connected device from connectedDeviceStream have no stream
    so i can't disconenct those devices..... T_T
    
    ■ Trying
    after Scenario 1, if i found already connected device
    then make connection and cancel...
    
    but can't get disconnected callback by ConnectionStateUpdate
    (both stream from connection and FlutterReactiveBle.instants's connectedDeviceStream)
    
    also can't scan that device...
    

    Can you do me a favor ?

    enhancement 
    opened by bysonstudio 23
  • Add option for discoverServices to return long UUID (128 bit)

    Add option for discoverServices to return long UUID (128 bit)

    Is your feature request related to a problem? Helo, I am working on ESP32 MCU and with custom services and characteristics using long UUID format. I want my android app to be a dynamic and show different widgets based on advertised characteristics.

    I have defined custom services on ESP32 like this:

    #define SERVICE_CREDENTIALS_UUID "56600000-BE5D-4370-877B-C4A2ACE639E8"
    #define SERVICE_STATE_UUID "B4D00000-DFAE-4F0B-9EEF-AEA76041E2D9"
    #define SERVICE_SETTINGS_UUID "7D700000-F94E-4D34-B701-483E29C79F55"
    

    and example of characteristics:

    #define CHARACTERISTIC_UUID_PH_MAX "50A00001-4E12-11EB-AE93-0242AC130002"
    #define CHARACTERISTIC_UUID_PH_MIN "50A00002-4E12-11EB-AE93-0242AC130002"
    #define CHARACTERISTIC_UUID_PH_CUR "50A00003-4E12-11EB-AE93-0242AC130002"
    

    When i am using another app to scan BLE device (like BLE Scanner) I am able to see long UUIDs and two mandatory services 0x1800 (Generic access) and 0x1801 (Generic attribute) which are only 16 bits. But when I try to use discoverServices in my app, all UUIDs are in short (16 bit) version:

    I/flutter (30058): Service = 1800 ([24, 0])
    I/flutter (30058): 
    I/flutter (30058): Service = 1801 ([24, 1])
    I/flutter (30058): 
    I/flutter (30058): Service = 0000 ([0, 0])
    I/flutter (30058): 
    I/flutter (30058): Service = 0000 ([0, 0])
    I/flutter (30058): 
    I/flutter (30058): Service = 0000 ([0, 0])
    

    Same goes for characteristics:

    I/flutter (30058): 	0001 ([0, 1])
    I/flutter (30058): 	0002 ([0, 2])
    I/flutter (30058): 	0003 ([0, 3])
    

    When I create Service UUID in app, it uses full 128 UUID:

    final Uuid SERVICE_UUID = Uuid.parse('7D700000-F94E-4D34-B701-483E29C79F55');
    print('looking for = ' + SERVICE_UUID.toString());
    print('looking for = ' + SERVICE_UUID.data.toString());
    
    /// Output
    I/flutter ( 3861): looking for = 7d700000-f94e-4d34-b701-483e29c79f55
    I/flutter ( 3861): looking for = [125, 112, 0, 0, 249, 78, 77, 52, 183, 1, 72, 62, 41, 199, 159, 85]
    

    Describe the solution you'd like I would love to be able enforce discoverServices to return long UUIDs when service/characteristic uses 128 bit UUID and short UUID when there is short UUID advertised. Maybe using an optional parameter: Future<List<DiscoveredService>> discoverServices(String deviceId, {bool useLongUuids})=> ...

    If this would take too much work, is it possible to at least add description that discoverServices returns only 16 bit UUID?

    Describe alternatives you've considered Since I can edit UUIDs on ESP32 I will just make sure that all 3rd and 4th bytes of UUID are unique and I will work with theirs abbreviations on the android side. But that solution is not possible when working with device where I can't change its UUIDs.

    bug Android 
    opened by Papajik 23
  • ios subscribeToCharacteristic crashes the app

    ios subscribeToCharacteristic crashes the app

    Describe the bug Subsrcibing to specific characteristic crashes ios app immediately. Android one works well with the same code.

    To Reproduce Steps to reproduce the behavior:

    1. use sample app

    2. change body of the function Future discoverServices(String deviceId) async to something like `final characteristic = QualifiedCharacteristic(serviceId: Uuid.parse('4c0719b0-c810-492b-87b1-63c6c3fd584f'), characteristicId: Uuid.parse('4c0719b3-c810-492b-87b1-63c6c3fd584f'), deviceId: deviceId);

      _ble.subscribeToCharacteristic(characteristic).listen((data) { print(data.toString()); }, onError: (dynamic error) { print(error); });`

    3. launch the app

    4. tap search button

    5. select device

    6. tap connect and wait until status changes

    7. tap Discover services

    8. app immediately crashes - tries to subsrcibe to characteristic

    Note: original code for discovering services works properly on both ios and android, so service and characteristics are discovered .

    Expected behavior Should receive data printed on console - Android works properly

    Smartphone / tablet

    • Device:iPhone XS
    • OS: iOS 14
    • Package version: 2.6.1+1

    Attached screenshot from xcode Screenshot 2020-11-04 at 23 42 18

    bug iOS 
    opened by dawidb-appdate 21
  • Build against Android 30 SDK Fails

    Build against Android 30 SDK Fails

    Build against Android 30 SDK Fails

    To Reproduce Steps to reproduce the behavior:

    1. Upgrade Package to 5.0.0 in project
    2. Build Against SDK 30, with minimum sdk 24
    3. Build fails with this message:
    Task failed with an exception.
    -----------
    * What went wrong:
    Execution failed for task ':app:bundleGooglePlayReleaseResources'.
    > A failure occurred while executing com.android.build.gradle.internal.res.Aapt2ProcessResourcesRunnable
       > Android resource linking failed
         ERROR:D:\Flutter\........\build\app\intermediates\bundle_manifest\googlePlayRelease\AndroidManifest.xml:35: AAPT: error: attribute android:usesPermissionFlags not found.
    
    bug Android 
    opened by pgiacomo69 19
  • subscribeToCharacteristic fails when Client Characteristic Config descriptor is not present

    subscribeToCharacteristic fails when Client Characteristic Config descriptor is not present

    I'm working on the example project of the library (https://github.com/PhilipsHue/flutter_reactive_ble/tree/master/example), I added a few buttons to test the API - readCharacteristic, writeCharacteristicWithResponse and subscribeToCharacteristic.

    Subscribing to notifications doesn't work as expected (read/write works well).

    Flow: scanForDevices connectToDevice/connectToAdvertisingDevice (tried both) subscribeToCharacteristic (after status is connected)

    Flow's code (serviceId ,readCharacteristicId & writeCharacteristicId are defined in the BLE server):

     final Uuid serviceId = Uuid.parse('06391ebb-4050-42b6-ab55-8282a15fa094');
     final Uuid readCharacteristicId = Uuid.parse('010d815c-031c-4de8-ac10-1ffebcf874fa'); 
     final Uuid writeCharacteristicId = Uuid.parse('f2926f0f-336a-4502-9948-e4e8fd2316e9');   
    
      Future<void> connect(String deviceId) async {
        if (_connection != null) {
          await _connection.cancel();
        }
    
        _connection = _ble
            .connectToDevice(
              id: deviceId,
              servicesWithCharacteristicsToDiscover: {
                serviceId: [readCharacteristicId, writeCharacteristicId]
              },
              connectionTimeout: const Duration(seconds: 10),
            )
            .listen(
              _deviceConnectionController.add,
            );
      }
    
    void subscribeCharacteristic(String deviceId) {
        final characteristic = QualifiedCharacteristic(
            serviceId: serviceId,
            characteristicId: readCharacteristicId,
            deviceId: deviceId);
    
        _ble.subscribeToCharacteristic(characteristic).listen((data) {
          // code to handle incoming data
          print('Data received $data');
        }, onError: (dynamic error) {
          // code to handle errors
          print('Subscribe error $error');
        });
      }
    
      Future<void> readCharacteristic(String deviceId) async {
        final characteristic = QualifiedCharacteristic(
            serviceId: serviceId,
            characteristicId: readCharacteristicId,
            deviceId: deviceId);
        await _ble.readCharacteristic(characteristic).then(
              printCharacteristic,
            );
      }
    
      Future<void> writeCharacteristic(String deviceId) async {
        final characteristic = QualifiedCharacteristic(
            serviceId: serviceId,
            characteristicId: writeCharacteristicId,
            deviceId: deviceId);
        await _ble.writeCharacteristicWithResponse(characteristic,
            value: [0xAD, 0xDE]).then(
          (value) => print('writeCharacteristic CB'),
        );
      }
    
    

    Debug output: I/flutter ( 4075): REACTIVE_BLE: Start subscribing to notifications for QualifiedCharacteristic(characteristicId: 010d815c-031c-4de8-ac10-1ffebcf874fa, serviceId: 06391ebb-4050-42b6-ab55-8282a15fa094, deviceId: 5F:99:E1:54:4A:89) D/BluetoothGatt( 4075): discoverServices() - device: 5F:99:E1:54:4A:89 D/BluetoothGatt( 4075): onSearchComplete() = Device=5F:99:E1:54:4A:89 Status=0 D/BluetoothGatt( 4075): setCharacteristicNotification() - uuid: 010d815c-031c-4de8-ac10-1ffebcf874fa enable: false I/flutter ( 4075): REACTIVE_BLE: Received CharacteristicValue(characteristic: QualifiedCharacteristic(characteristicId: 010d815c-031c-4de8-ac10-1ffebcf874fa, serviceId: 06391ebb-4050-42b6-ab55-8282a15fa094, deviceId: 5F:99:E1:54:4A:89), result: CharacteristicValue) I/flutter ( 4075): Subscribe error Exception: GenericFailure(code: CharacteristicValueUpdateError.unknown, message: "Cannot find client characteristic config descriptor (code 2) with characteristic UUID 010d815c-031c-4de8-ac10-1ffebcf874fa")

    Please explain: Why is the 'enabled' boolean (setCharacteristicNotification) false? how can I set it to true? What is the reason for the "Subscribe error Exception"? Am I supposed to configure a descriptor? if so, how?

    Additional info

    My Android based BLE server, creation code:

        UUID SENSOR_SERVICE = UUID.fromString("06391ebb-4050-42b6-ab55-8282a15fa094"); // Sensor Service 
        UUID DATA_R = UUID.fromString("010d815c-031c-4de8-ac10-1ffebcf874fa");                        // Readable Characteristic 
        UUID CLIENT_CONFIG = UUID.fromString("7385e060-b9a8-4853-848d-c70178b0e01e");  // Config Descriptor
        UUID DATA_W = UUID.fromString("f2926f0f-336a-4502-9948-e4e8fd2316e9");                  // Writable Characteristic
        
        BluetoothGattService service = new BluetoothGattService(SensorProfile.SENSOR_SERVICE,
                BluetoothGattService.SERVICE_TYPE_PRIMARY);
        
        // Readable Data characteristic
        BluetoothGattCharacteristic dataR = new BluetoothGattCharacteristic(DATA_R,
                //Read-only characteristic, supports notifications
                 BluetoothGattCharacteristic.PROPERTY_NOTIFY |
                            BluetoothGattCharacteristic.PROPERTY_READ |
                            BluetoothGattCharacteristic.PROPERTY_INDICATE |
                            BluetoothGattCharacteristic.PROPERTY_BROADCAST,
                BluetoothGattCharacteristic.PERMISSION_READ);
        
          //Read/write descriptor
          BluetoothGattDescriptor configDescriptor = new BluetoothGattDescriptor(CLIENT_CONFIG,
              BluetoothGattDescriptor.PERMISSION_READ);
        
          dataR.addDescriptor(configDescriptor);
          service.addCharacteristic(dataR);
        
          // Writeable Data characteristic
          BluetoothGattCharacteristic dataW = new BluetoothGattCharacteristic(DATA_W,
                  BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);
          service.addCharacteristic(dataW);
    

    My Android based BLE client (notifications works as expected), code:

     BluetoothGattService service = mBluetoothGatt.getService(SENSOR_SERVICE);
          // Get the counter characteristic
          BluetoothGattCharacteristic characteristic = service.getCharacteristic(DATA_R);
        
          // Enable notifications for this characteristic locally
          mBluetoothGatt.setCharacteristicNotification(characteristic, true);
        
          // Write on the config descriptor to be notified when the value changes
          BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CONFIG);
          descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
          mBluetoothGatt.writeDescriptor(descriptor);
    

    Flutter ble client: https://github.com/LironKomfort/reactive_ble_test

    BLE android client/server projects: https://github.com/LironKomfort/android_ble_server_client

    Client tested on Android version 9 (Xiaomi mi6 + Pixel 4A) Server tested on Android version 7.1

    enhancement Android 
    opened by LironKomfort 18
  • Get rid of mockito

    Get rid of mockito

    The problem is that Mockito needs codegen to comply to null safety. I would like to see if we can replace our mocks with stubs (also need to extract interfaces). This help us to not need to generate for our tests and we can start migrating and testing our library for null safety in Dart.

    opened by remonh87 18
  • unsubscribing and discoverServices throws error on IOS with custom nrf firmware

    unsubscribing and discoverServices throws error on IOS with custom nrf firmware

    Describe the bug This issue occurs only on IOS once you try to reconnect to a device : The discoverServices method throws an error : PlatformException(reactive_ble_mobile.Central.(unknown context at $1010530e4).Failure:2, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $1010530e4).Failure error 2.), {}, null)

    How i connect to a device :

    connectionStream = flutterReactiveBle.connectToDevice(id: address,
            servicesWithCharacteristicsToDiscover: servicesWithChars,
            connectionTimeout: const Duration(seconds: 5)).listen((event) {
              try {
                _deviceConnectionController.add(event);
              }catch(connectionError){
                print("Could not add event on closed stream!");
              }
          if (!tryingToConnect) {
            tryingToConnect = true;
            _discoverServicesAndCharacteristics(
                address, onConnectionResult, true, () {});
          }else{
            print("Cannot connect because i am already trying to connect!");
          }
        }, onError: (dynamic err) {
              print("Found error while connecting to device : ${err.toString()}");
        });
    

    How i discover services: (error occurs here)

      flutterReactiveBle.discoverServices(id)
                              .onError((error, stackTrace) {
                                      print("Failed to discover services : ${error.toString()} \n ${stackTrace.toString()}");
                                      return [];
                              }).then((value) {
                                     print("received values");
                                     ....
                                     ....
                                     ....
                               });
    

    How i disconnect from the device :

        try {
          await subscription.cancel();
          print("cancelling connection...");
          await connectionStream.cancel();
          tryingToConnect = false;
          print("not trying to connect anymore 1");
        } on Exception catch (e, _) {
          print(Error disconnecting from a device $e");
        }finally{
          if(Platform.isIOS){
            _deviceConnectionController.add(
              ConnectionStateUpdate(
                deviceId: kubeId,
                connectionState: DeviceConnectionState.disconnected,
                failure: null,
              ),
            );
          }
        }
    

    So the first time i am able to connect to the device, i am able to send and receive data and i am able to disconnect from the device though only on IOS it throws this error when i try to disconnect : Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.PluginError:7, The operation couldn’t be completed. (reactive_ble_mobile.PluginError error 7.), {}, null)

    And this may cause the discoverService to throw the other error, so i tried to re-assign the FlutterReactiveBle once disconnected but it still occurs. Then once i try to connect again it thows the error i posted before, PlatformException(reactive_ble_mobile.Central.(unknown context at $1010530e4).Failure:2, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $1010530e4).Failure error 2.), {}, null) Stacktrace : `StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607)

    MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156)

    FutureExtensions.onError. (dart:async/future.dart:795)

    `

    On Android it works perfectly and throws no error

    Did I do something wrong, or is there an issue with IOS?

    To Reproduce Steps to reproduce the behavior:

    1. Connect to one / many devices using connectTo() / connectToAdvertisingDevice()
    2. Read from / write to / subscribe to a protected / non-protected characteristic
    3. Disconnect from the device
    4. Reconnect to the device
    5. The error is thrown

    Expected behavior Once i try to re-connect to the device, it should work like the first time i tried to connect

    Smartphone / tablet

    • Device: [e.g. iPhone 6]
    • OS: [e.g. iOS 12]

    Peripheral device

    • nRF52832
    • Does it run a custom firmware / software: yes
    bug awaiting response 
    opened by riccardocescon 17
  • iOS writeCharacteristicWithoutResponse gives characteristic not writable error

    iOS writeCharacteristicWithoutResponse gives characteristic not writable error

    Describe the bug I'm running the example app for the package. I connect to my custom peripheral and select my (protected) writable characteristic. I enter a value into the value text field and press "Without response" button. I see the exception:

    _Exception (Exception: GenericFailure(code: WriteCharacteristicFailure.unknown, message: "The characteristic 6E400002-B5A3-F393-E0A9-E50E24DCCA9E of the service 6E400001-B5A3-F393-E0A9-E50E24DCCA9E of the peripheral 4F19023B-EB8D-A5C6-CBFC-750B2E04A481 is not writable"))

    Pressing the "With response" is successful, but I don't want to use this in my application as I'm sending a lot of data to my characteristic and with response adds a lot of overhead and roughly doubles my transmission time.

    To Reproduce Steps to reproduce the behavior:

    1. Forget device in iOS bluetooth settings
    2. Connect to device and discover services
    3. Select characteristic and send value "with response". This triggers iOS to show the "Bluetooth Pairing Request" dialog
    4. Pair with the device. I now see Output: Ok
    5. Send value again "with response". Again I see Output: Ok but no pairing dialog, indicating that I am successfully paired with the device
    6. Send value again "without response". I get the exception described above

    Expected behavior I expect to be able to send data using "writeCharacteristicWithoutResponse"

    I can successfully communicate with the peripheral from the same iOS device with nRF connect and BLE Scanner apps

    Smartphone / tablet

    • Device: iPhone SE
    • OS: iOS 13.7
    • Package version: 5.0.2

    Peripheral device

    • Custom

    Additional context Works flawlessly on Android, I'm only having a problem with iOS

    opened by andrewdixon1000 15
  • PluginController.swift Assertion failed / iOS

    PluginController.swift Assertion failed / iOS

    After connecting to bluetooth i got this error:

    flutter_reactive_ble/PluginController.swift:86: Assertion failed Runner[36443:1970108] flutter_reactive_ble/PluginController.swift:86: Assertion failed Screen Shot 2021-07-05 at 12 22 18 AM

    opened by MazenCoder 15
  • minSdk API lvl 24 as a lib requirement

    minSdk API lvl 24 as a lib requirement

    Describe the bug The libs minSdk requirement for Android should be lowered, since BLE has been introduced in API level 18/19, but the library is requiring API level 24

    To Reproduce Try to build the example app with minSdk set to API lvl 19

    Expected behavior Should be building while i drink my coffee

    • [x] I tried doing the same with a general BLE scanner application (e.g. nRF Connect) and it exhibits the expected behavior as described above

    Smartphone / tablet

    • Device: Nexus 4, 4.4 Kitkat

    Peripheral device

    Additional context

    enhancement Android 
    opened by vsxed 15
  • scanForDevices() returns incorrect input

    scanForDevices() returns incorrect input

    Describe the bug I am building an application which prints ID, Name, RSSI and ServiceUUID of available BLE's

    
      void bleScanner() {
        print('Into the function bleScanner()');
        final flutterReactiveBle = FlutterReactiveBle();
        flutterReactiveBle.scanForDevices(withServices: []).listen(
          (device) {
            print('The program found some devices!');
            print(
                "${device.id}, ${device.name}, ${device.rssi}, ${device.serviceUuids}");
          },
        );
      }
    
    

    This application runs fine, but if I simulate an iBeacon in my phone, the generated UUID does not show up in the output.

    Smartphone / tablet

    • Device: iPhone XR
    • OS: iOS 16
    • Package version: 5.0.3

    Peripheral device

    • Vendor, model: iPhone XR
    • Does it run a custom firmware / software: no
    opened by akashShanmugraj 0
  • 5.0.3 version does not can't scan BLE Beacons devices on Android 12+

    5.0.3 version does not can't scan BLE Beacons devices on Android 12+

    When use a flutter_reactive_ble scanner does not see any Beacon devices on Android 12+ I tried to scan for devices - scanner does not detect any BLE Beacons devices on Android 12+, while it perfectly detects all of BLE Beacon devices on Android 11 and lower.

    To Reproduce Steps to reproduce the behavior:

    1. Clone repo
    2. Run flutter pub get and flutter packages pub run build_runner build --delete-conflicting-outputs in folders: example, packages/flutter_reactive_ble, packages/reactive_ble_mobile, packages/reactive_ble_platform_interface.
    3. Run an app on Android 12+
    4. Scan for devices near the Beacon sensors.

    Expected behavior While scanning all BLE Beacons devices must be detected

    Smartphone

    • Device: [SM M127F - Samsung Galaxy M12 32GB]
    • OS: [Android 12]

    Peripheral device

    • Vendor, model: [AprilBrother, model number 2.0.4]
    • Does it run a custom firmware / software: no, firm revision 4.0.8

    Additional context To start an app from example I had to fix some bugs

    1. Added an import import 'dart:typed_data'; to files:
    packages/reactive_ble_mobile/lib/src/converter/protobuf_converter.dart
    packages/reactive_ble_mobile/test/reactive_ble_platform_test.dart
    
    1. Modify an AndroidManifest file like this, otherwise an app doesn't even start
    Screenshot 2022-12-25 at 13 20 29
    opened by fufylev 1
  • Is it possible to get all bytes from ScanRecord on Android?

    Is it possible to get all bytes from ScanRecord on Android?

    Is your feature request related to a problem? (please describe) I'm trying to use this library to collect the manufacturer data on iOS and Android. But I noticed the manufacturer data of the same device received by iOS and Android is quite different. On iOS, I'm able to get the complete raw data. So is there any way to get a byte array of ScanRecord.getBytes() on Android?

    Describe the solution you'd like We could have another property "rawData" in the DiscoveredDevice.

    Describe alternatives you've considered N/A

    Additional context Thank you for the time to improve this library and make it work smoothly on iOS and Android.

    opened by GsMoMo 2
  • Optional setting of setLegacy() to prevent gaps in scan results from legacy advertisers on Android

    Optional setting of setLegacy() to prevent gaps in scan results from legacy advertisers on Android

    5.0.3 adds .setLegacy(false) to scan settings by default, while not a bug, this setting can cause long gaps in scan results from fast advertising legacy devices on Android and changes behaviour of our app which listens to adv. beacons.

    In 5.0.2 without setLegacy() our app would receive 10-20 adv per second continuously without gaps, in 5.0.3 we see 10-20 adv per second for 7-10 seconds followed by 2-4 seconds of no results (repeated)

    Consider providing a means to optionally set legacy adv. in scan setting.

    opened by anthonyhunter 2
  • Remove pubspec.lock in library packages

    Remove pubspec.lock in library packages

    Is there any particular reason to include pubspec.lock in library packages? While it is fine for the example app, libraries generally should not include lockfiles. See What not to commit.

    I'd be happy to provide a PR and grab some low hanging fruits.

    opened by rfuerst87 0
Releases(5.0.3)
This flutter app will help you to connect to Bluetooth Devices (like, HC-05)

Flutter Bluetooth NOTE: This is the updated version of the app (using flutter_bluetooth_serial 0.2.2). This version has much fewer bugs and provides a

Riyad Al-Ali 1 Jun 5, 2022
FlutterBleLib - A library for all your Bluetooth Low Energy needs in Flutter.

FlutterBleLib A library for all your Bluetooth Low Energy needs in Flutter. Internally utilises Polidea's MultiPlatformBleAdapter, which runs on RxAnd

null 4 Jun 10, 2022
Bluetooth Low Energy library for Flutter with support for simulating peripherals

FlutterBleLib A library for all your Bluetooth Low Energy needs in Flutter. Internally utilises Polidea's MultiPlatformBleAdapter, which runs on RxAnd

intent 509 Jan 3, 2023
I have created app to connect printer with bluetooth. And I already fix library bugs

flutter_bluetooth_printer A new Flutter application. Getting Started This project is a starting point for a Flutter application. A few resources to ge

Bounphone KOSADA 1 May 11, 2022
Bluetooth plugin for Flutter

Introduction FlutterBlue is a bluetooth plugin for Flutter, a new app SDK to help developers build modern multi-platform apps. Alpha version This libr

Paul DeMarco 2.2k Jan 5, 2023
Flutter beacons plugin for Android and iOS.

Beacons Flutter plugin to work with beacons. Supports Android API 16+ and iOS 8+. Features: Automatic permission management Ranging Monitoring (includ

Loup 76 Jan 6, 2023
Flutter NFC reader plugin for iOS and Android

Flutter NFC Reader & Writer A new flutter plugin to help developers looking to use internal hardware inside iOS or Android devices for reading and wri

Matteo Crippa 321 Dec 30, 2022
A Flutter plugin for turning your device into a beacon.

Beacon Broadcast plugin for Flutter A Flutter plugin for turning your device into a beacon. Usage To use this plugin, add beacon_broadcast as a depend

Paulina Szklarska 75 Dec 14, 2022
Flutter plugin for accessing the NFC features on Android and iOS.

nfc_manager Flutter plugin for accessing the NFC features on Android and iOS. Note: This plugin depends on NFCTagReaderSession (requires iOS 13.0 or l

null 126 Jan 1, 2023
Ready for Building Production-Ready Healthcare/ Doctor Consult Android and iOS app UI using Flutter.

Production-Ready Doctor Consultant App - Flutter UI Watch it on YouTube Packages we are using: flutter_svg: link Complete Source code (Patreon) In thi

Abu Anwar 211 Jan 1, 2023
Using Bluetooth plugin in Flutter (flutter_bluetooth_serial)

Flutter Bluetooth NOTE: This is the updated version of the app (using flutter_bluetooth_serial 0.2.2). This version has much fewer bugs and provides a

Souvik Biswas 179 Nov 22, 2022
ESC/POS (thermal, receipt) printing for Flutter & Dart (Android/iOS)

esc_pos_bluetooth The library allows to print receipts using a Bluetooth printer. For WiFi/Ethernet printers, use esc_pos_printer library. TODO (PRs a

Andrey 175 Jan 6, 2023
A Flutter Template to communicate with an esp32 over bluetooth

Flutter Esp32 Bluetooth Template Changes in android/ [1 if you take the code to an other project, 2 still nessesarely]: Change minSdkVersion from 16 t

0x4d/Martin Loretz 23 Dec 20, 2022
Flutter basic implementation for Classical Bluetooth (only RFCOMM for now)

flutter_bluetooth_serial Flutter basic implementation for Classical Bluetooth (only RFCOMM for now). Features The first goal of this project, started

null 1 Nov 7, 2022
Flutter library that handles BLE operations for multiple devices

Flutter reactive BLE library Flutter library that handles BLE operations for multiple devices. Usage The reactive BLE lib supports the following: BLE

null 1 Apr 12, 2022
null 5 Nov 21, 2022
A flutter plugin for bluebooth ble device connect and control.

flutter_blue_elves A flutter plugin witch includes platform-specific implementation code for Android and/or iOS to connect and control bluetooth ble d

PineappleOilPrince 29 Dec 30, 2022
Flutter error catching & handling plugin. Handles and reports exceptions in your app!

Catcher Catcher is Flutter plugin which automatically catches error/exceptions and handle them. Catcher offers multiple way to handle errors. Catcher

Jakub 697 Jan 7, 2023
This example handles HTTP GET requests by responding with 'Hello, World!'

Hello world example This example handles HTTP GET requests by responding with 'Hello, World!'. // lib/functions.dart import 'package:functions_framewo

TryIt (김동현) 0 May 25, 2022
Dart library for some Turkish language specific operations.

turkish This library provides these functions for Turkish language for Dart: Converting strings to lower, upper and title case. Regular and ignore cas

Ahmet A. Akın 39 Dec 27, 2022