flutter_reactive_ble 1.0.2

Flutter reactive BLE library #

Flutter library that handles BLE operations for multiple devices.

Work in progress #

The library is feature complete but we are working at the moment on improving documentation and the example app.

Usage #

The reactive BLE lib supports the following:

  • BLE device discovery
  • 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

Device discovery #

Discovering BLE devices should be done like this:

reactivebleclient.scanForDevices(withService: uuid, scanMode: ScanMode.lowLatency).listen((device) {
      //code for handling results
    }, onError: () {
      //code for handling error
    });
  

The withservice parameter is required. The parameter scanmode is only used in Android and follows the conventions described in Android scansettings reference. If no scanmode is specified the library will use the balanced scanmode as reference.

Establishing connection #

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

reactiveBleClient.connectToDevice(
      id: 'AA:BB:CC:DD:EE:FF', 
      servicesWithCharacteristicsToDiscover: {serviceUuid: [char1, char2]},
      connectionTimeout: const Duration(seconds:  2),
    ).listen((connectionUpdate) {
      //code to handle connection update
    }, onError: (dynamic error) {
      //code to handle error
    });

Use for the required id parameter the device id retrieved from device discovery. For iOS this should be a UUID and for Android thisis a MAC address. When first writing or reading a BLE characteristic after establishing a connection it can take a while because the BLE stack needs to discover all services. When supplying a map with services and characteristic UUIDs you want to discover, you can speedup the usage of those services because they will be discovered when establishing a connection. This functionality is only supported by iOS. You can specify a connectionTimeout when the client will provide an error in case the connection cannot be established within the specified time. However this does not mean that the client has cancelled the connection request on the level of the BLE stack.

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 when it is found connect to it.

  reactiveBleClient.connectToAdvertisingDevice(
      id: 'AA:BB:CC:DD:EE:FF', 
      withService: serviceUuid,
      prescanDuration: const Duration(seconds: 5), 
      servicesWithCharacteristicsToDiscover: {serviceUuid: [char1, char2]},
      connectionTimeout: const Duration(seconds:  2),
    ).listen((connectionUpdate) {
      //code to handle connection update
    }, onError: (dynamic error) {
      //code to handle error
    });

Besides the normal connection parameters that are described at above this function also has 2 additional required parameters: withService 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: 'AA:BB:CC:DD:EE:FF');
final response = await reactiveBleClient.readCharacteristic(characteristic);

Write with response #

Write a value to characteristic and await the reaponse. The return value is a List<Int>.

final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: 'AA:BB:CC:DD:EE:FF');
final response = await reactiveBleClient.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 it is recommended to do a writeWithResponse each x times.

final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: 'AA:BB:CC:DD:EE:FF');
reactiveBleClient.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: 'AA:BB:CC:DD:EE:FF');
   reactiveBleClient.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 reactiveBleClient.requestMtu(deviceId: 'AA:BB:CC:DD:EE:FF', 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 reactiveBleClient.requestConnectionPriority(deviceId: 'AA:BB:CC:DD:EE:FF', 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 usage is not encouraged by the Android team

await reactiveBleClient.clearGattCache('AA:BB:CC:DD:EE:FF');

1.0.2 #

  • Fix crash on clear Gattcache

1.0.1 #

  • Fixes #5 Undeliverable exception.

  • Small fixes for example app.

1.0.0+1 #

  • Update homepage

1.0.0 #

  • Initial Open Source release.

example/README.md

flutter_reactive_ble #

Demonstrates how to use the flutter_reactive_ble plugin.

Getting Started #

For help getting started with Flutter, view our online documentation.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  flutter_reactive_ble: ^1.0.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
69
Health:
Code health derived from static analysis. [more]
97
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
84
Learn more about scoring.

We analyzed this package on Feb 19, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.5
  • Flutter: 1.12.13+hotfix.7

Health suggestions

Fix lib/src/model/discovered_device.g.dart. (-2.96 points)

Analysis of lib/src/model/discovered_device.g.dart reported 6 hints, including:

line 39 col 8: Name non-constant identifiers using lowerCamelCase.

line 39 col 23: Name non-constant identifiers using lowerCamelCase.

line 41 col 8: Name non-constant identifiers using lowerCamelCase.

line 41 col 25: Name non-constant identifiers using lowerCamelCase.

line 43 col 8: Name non-constant identifiers using lowerCamelCase.

Format lib/src/model/discovered_device.dart.

Run flutter format to format lib/src/model/discovered_device.dart.

Format lib/src/rx_ext/repeater.dart.

Run flutter format to format lib/src/rx_ext/repeater.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.0-dev <3.0.0
collection ^1.14.11 1.14.11 1.14.12
flutter 0.0.0
functional_data ^0.2.3 0.2.3
meta ^1.1.8 1.1.8
protobuf ^1.0.1 1.0.1
Transitive dependencies
fixnum 0.10.11
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
build_runner ^1.7.2
dependency_validator ^1.4.2
flutter_reactive_ble_example
flutter_test
functional_data_generator ^0.2.3
mockito ^4.1.1