flutter_blue_plus
v1.36.8Flutter plugin for connecting and communicating with Bluetooth Low Energy devices.
Package archive: https://pubdev.letsnova.ru/api/archives/flutter_blue_plus/1.36.8.tar.gz
dart pub add flutter_blue_plusReadme
Sponsor
FlutterBluePlus is sponsored by Jamcorder.
Note: this plugin is continuous work from FlutterBlue.
Migrating from FlutterBlue? See Migration Guide
Contents
- Introduction
- Usage
- Getting Started
- Using Ble in App Background
- API Reference
- Debugging
- Mocking
- Common Problems
Introduction
FlutterBluePlus is a Bluetooth Low Energy plugin for Flutter.
It supports BLE Central Role only (most common).
If you need BLE Peripheral Role, you should check out FlutterBlePeripheral, or bluetooth_low_energy.
Tutorial
If you are new to Bluetooth, you should start by reading BLE tutorials.
β Bluetooth Classic is not supported β
i.e. Arduino HC-05 & HC-06, speakers, headphones, mice, keyboards, gamepads, and more are not supported. These all use Bluetooth Classic.
Also, iBeacons are not supported on iOS. Apple requires you to use CoreLocation.
Cross-Platform Bluetooth Low Energy
FlutterBluePlus supports nearly every feature on all supported platforms: iOS, macOS, Android, Linux, Web.
No Dependencies
FlutterBluePlus has zero dependencies besides Flutter, Android, iOS, and macOS themselves.
This makes FlutterBluePlus very stable, and easy to maintain.
Windows Support
Use flutter_blue_plus_windows if you need Windows support.
It is maintained by @chan150. Eventually the goal is to merge.
β Stars β
Please star this repo & on pub.dev. We all benefit from having a larger community.
Discord π¬
There is a community Discord server. (Link)
Example
FlutterBluePlus has a beautiful example app, useful to debug issues.
cd ./example
flutter run
Versioning
flutter_blue_plus uses Traditional Versioning
BIG.MEDIUM.SMALL:
BIG: Significant overhauls. e.g.1.0.0->2.0.0.MEDIUM: Moderate improvements, feature updates, breaking chages. e.g.1.0.0->1.1.0.SMALL: Small fixes, patches, or refinements.1.0.0->1.0.1.
flutter_blue_plus_android, flutter_blue_plus_darwin, flutter_blue_plus_linux, flutter_blue_plus_platform_interface, flutter_blue_plus_web use Semantic Versioning.
MAJOR.MINOR.PATCH:
MAJOR: Breaking API changes. e.g.1.0.0->2.0.0.MINOR: New features. e.g.1.0.0->1.1.0.PATCH: Bug fixes. e.g.1.0.0->1.0.1.
Usage
π₯ Error Handling π₯
Flutter Blue Plus takes error handling seriously.
Every error returned by the native platform is checked and thrown as an exception where appropriate.
Streams: Streams returned by FlutterBluePlus never emit any errors and never close. There's no need to handle onError or onDone for stream.listen(...). The one exception is FlutterBluePlus.scanResults, which you should handle onError.
Set Log Level
// if your terminal doesn't support color you'll see annoying logs like `\x1B[1;35m`
FlutterBluePlus.setLogLevel(LogLevel.verbose, color:false);
// optional
FlutterBluePlus.logs.listen((String s){
// send logs anywhere you want
});
Setting LogLevel.verbose shows all data in and out.
β« = function name
π£ = args to platform
π‘ = data from platform
Bluetooth On & Off
Note: On iOS, a "This app would like to use Bluetooth" system dialogue appears on first call to any FlutterBluePlus method.
// first, check if bluetooth is supported by your hardware
// Note: The platform is initialized on the first call to any FlutterBluePlus method.
if (await FlutterBluePlus.isSupported == false) {
print("Bluetooth not supported by this device");
return;
}
// handle bluetooth on & off
// note: for iOS the initial state is typically BluetoothAdapterState.unknown
// note: if you have permissions issues you will get stuck at BluetoothAdapterState.unauthorized
var subscription = FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
print(state);
if (state == BluetoothAdapterState.on) {
// usually start scanning, connecting, etc
} else {
// show an error to the user, etc
}
});
// turn on bluetooth ourself if we can
// for iOS, the user controls bluetooth enable/disable
if (!kIsWeb && Platform.isAndroid) {
await FlutterBluePlus.turnOn();
}
// cancel to prevent duplicate listeners
subscription.cancel();
Scan for devices
If your device is not found, see Common Problems.
Note: It is recommended to set scan filters to reduce main thread & platform channel usage.
// listen to scan results
// Note: `onScanResults` clears the results between scans. You should use
// `scanResults` if you want the current scan results *or* the results from the previous scan.
var subscription = FlutterBluePlus.onScanResults.listen((results) {
if (results.isNotEmpty) {
ScanResult r = results.last; // the most recently found device
print('${r.device.remoteId}: "${r.advertisementData.advName}" found!');
}
},
onError: (e) => print(e),
);
// cleanup: cancel subscription when scanning stops
FlutterBluePlus.cancelWhenScanComplete(subscription);
// Wait for Bluetooth enabled & permission granted
// In your real app you should use `FlutterBluePlus.adapterState.listen` to handle all states
await FlutterBluePlus.adapterState.where((val) => val == BluetoothAdapterState.on).first;
// Start scanning w/ timeout
// Optional: use `stopScan()` as an alternative to timeout
await FlutterBluePlus.startScan(
withServices:[Guid("180D")], // match any of the specified services
withNames:["Bluno"], // *or* any of the specified names
timeout: Duration(seconds:15));
// wait for scanning to stop
await FlutterBluePlus.isScanning.where((val) => val == false).first;
Connect to a device
// listen for disconnection
var subscription = device.connectionState.listen((BluetoothConnectionState state) async {
if (state == BluetoothConnectionState.disconnected) {
// 1. typically, start a periodic timer that tries to
// reconnect, or just call connect() again right now
// 2. you must always re-discover services after disconnection!
print("${device.disconnectReason?.code} ${device.disconnectReason?.description}");
}
});
// cleanup: cancel subscription when disconnected
// - [delayed] This option is only meant for `connectionState` subscriptions.
// When `true`, we cancel after a small delay. This ensures the `connectionState`
// listener receives the `disconnected` event.
// - [next] if true, the the stream will be canceled only on the *next* disconnection,
// not the current disconnection. This is useful if you setup your subscriptions
// before you connect.
device.cancelWhenDisconnected(subscription, delayed:true, next:true);
// Connect to the device
await device.connect();
// Disconnect from device
await device.disconnect();
// cancel to prevent duplicate listeners
subscription.cancel();
Auto Connect
Connects whenever your device is found.
// enable auto connect
// - note: autoConnect is incompatible with mtu argument, so you must call requestMtu yourself
await device.connect(autoConnect:true, mtu:null)
// wait until connection
// - when using autoConnect, connect() always returns immediately, so we must
// explicity listen to `device.connectionState` to know when connection occurs
await device.connectionState.where((val) => val == BluetoothConnectionState.connected).first;
// disable auto connect
await device.disconnect()
Save Device
To save a device between app restarts, just write the remoteId to a file.
Now you can connect without needing to scan again, like so:
final String remoteId = await File('/remoteId.txt').readAsString();
var device = BluetoothDevice.fromId(remoteId);
// AutoConnect is convenient because it does not "time out"
// even if the device is not available / turned off.
await device.connect(autoConnect: true);
MTU
On Android, we request an mtu of 512 by default during connection (see: connect function arguments).
On iOS & macOS, the mtu is negotiated automatically, typically 135 to 255.
final subscription = device.mtu.listen((int mtu) {
// iOS: initial value is always 23, but iOS will quickly negotiate a higher value
print("mtu $mtu");
});
// cleanup: cancel subscription when disconnected
device.cancelWhenDisconnected(subscription);
// You can also manually change the mtu yourself.
if (!kIsWeb && Platform.isAndroid) {
await device.requestMtu(512);
}
Discover services
// Note: You must call discoverServices after every re-connection!
List<BluetoothService> services = await device.discoverServices();
services.forEach((service) {
// do something with service
});
Read Characteristics
// Reads all characteristics
var characteristics = service.characteristics;
for(BluetoothCharacteristic c in characteristics) {
if (c.properties.read) {
List<int> value = await c.read();
print(value);
}
}
Write Characteristic
// Writes to a characteristic
await c.write([0x12, 0x34]);
allowLongWrite: To write large characteristics (up to 512 bytes) regardless of mtu, use allowLongWrite:
/// allowLongWrite should be used with caution.
/// 1. it can only be used *with* response to avoid data loss
/// 2. the peripheral device must support the 'long write' ble protocol.
/// 3. Interrupted transfers can leave the characteristic in a partially written state
/// 4. If the mtu is small, it is very very slow.
await c.write(data, allowLongWrite:true);
splitWrite: To write lots of data (unlimited), you can define the splitWrite function.
import 'dart:math';
// split write should be used with caution.
// 1. due to splitting, `characteristic.read()` will return partial data.
// 2. it can only be used *with* response to avoid data loss
// 3. The characteristic must be designed to support split data
extension splitWrite on BluetoothCharacteristic {
Future<void> splitWrite(List<int> value, {int timeout = 15}) async {
int chunk = min(device.mtuNow - 3, 512); // 3 bytes BLE overhead, 512 bytes max
for (int i = 0; i < value.length; i += chunk) {
List<int> subvalue = value.sublist(i, min(i + chunk, value.length));
await write(subvalue, withoutResponse:false, timeout: timeout);
}
}
}
Subscribe to a characteristic
If onValueReceived is never called, see Common Problems in the README.
final subscription = characteristic.onValueReceived.listen((value) {
// onValueReceived is updated:
// - anytime read() is called
// - anytime a notification arrives (if subscribed)
});
// cleanup: cancel subscription when disconnected
device.cancelWhenDisconnected(subscription);
// subscribe
// Note: If a characteristic supports both **notifications** and **indications**,
// it will default to **notifications**. This matches how CoreBluetooth works on iOS.
await characteristic.setNotifyValue(true);
Last Value Stream
lastValueStream is an alternative to onValueReceived. It emits a value any time the characteristic changes, including writes.
It is very convenient for simple characteristics that support both WRITE and READ (and/or NOTIFY). e.g. a "light switch toggle" characteristic.
final subscription = characteristic.lastValueStream.listen((value) {
// lastValueStream` is updated:
// - anytime read() is called
// - anytime write() is called
// - anytime a notification arrives (if subscribed)
// - also when first listened to, it re-emits the last value for convenience.
});
// cleanup: cancel subscription when disconnected
device.cancelWhenDisconnected(subscription);
// enable notifications
await characteristic.setNotifyValue(true);
Read and write descriptors
// Reads all descriptors
var descriptors = characteristic.descriptors;
for(BluetoothDescriptor d in descriptors) {
List<int> value = await d.read();
print(value);
}
// Writes to a descriptor
await d.write([0x12, 0x34])
Services Changed Characteristic
FlutterBluePlus automatically listens to the Services Changed Characteristic (0x2A05)
In FlutterBluePlus, we call it onServicesReset because you must re-discover services.
// - uses the GAP Services Changed characteristic (0x2A05)
// - you must call discoverServices() again
device.onServicesReset.listen(() async {
print("Services Reset");
await device.discoverServices();
});
Get Connected Devices
Get devices currently connected to your app.
List<BluetoothDevice> devs = FlutterBluePlus.connectedDevices;
for (var d in devs) {
print(d);
}
Get System Devices
Get devices connected to the system by any app.
Note: before you can communicate, you must connect your app to these devices
// `withServices` required on iOS, ignored on android
List<Guid> withServices = [Guid("180F")]; // e.g. Battery Service
List<BluetoothDevice> devs = await FlutterBluePlus.systemDevices(withServices);
for (var d in devs) {
await d.connect(); // Must connect *our* app to the device
await d.discoverServices();
}
Create Bond (Android Only)
Note: calling this is usually not necessary!! The platform will do it automatically.
However, you can force the popup to show sooner.
final bsSubscription = device.bondState.listen((value) {
print("$value prev:{$device.prevBondState}");
});
// cleanup: cancel subscription when disconnected
device.cancelWhenDisconnected(bsSubscription);
// Force the bonding popup to show now (Android Only)
await device.createBond();
// remove bond
await device.removeBond();
Events API
Access streams from all devices simultaneously.
There are streams for:
- events.onConnectionStateChanged
- events.onMtuChanged
- events.onReadRssi
- events.onServicesReset
- events.onDiscoveredServices
- events.onCharacteristicReceived
- events.onCharacteristicWritten
- events.onDescriptorRead
- events.onDescriptorWritten
- events.onNameChanged (iOS Only)
- events.onBondStateChanged (Android Only)
// listen to *any device* connection state changes
FlutterBluePlus.events.onConnectionStateChanged.listen((event)) {
print('${event.device} ${event.connectionState}');
}
Mocking
To mock FlutterBluePlus for development, refer to the Mocking Guide.
Getting Started
Add the flutter_blue_plus plugin
We recommend that you pin to a specific version of the flutter_blue_plus plugin for maximum stability and to avoid small breaking changes.
flutter pub add flutter_blue_plus:x.y.z
flutter_blue_plus is a federated plugin with endorsed platform implementations therefore you only need to add the "app-facing package" to your pubspec.yaml file.
Change the minSdkVersion for Android
flutter_blue_plus is compatible only from version 21 of Android SDK so you should change this in android/app/build.gradle:
android {
defaultConfig {
minSdkVersion: 21
Add permissions for Android (No Location)
In the android/app/src/main/AndroidManifest.xml add:
<!-- Tell Google Play Store that your app uses Bluetooth LE
Set android:required="true" if bluetooth is necessary -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
<!-- New Bluetooth permissions in Android 12
https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- legacy for Android 11 or lower -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
<!-- legacy for Android 9 or lower -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
Add permissions for Android (With Fine Location)
If you want to use Bluetooth to determine location, or support iBeacons.
In the android/app/src/main/AndroidManifest.xml add:
<!-- Tell Google Play Store that your app uses Bluetooth LE
Set android:required="true" if bluetooth is necessary -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
<!-- New Bluetooth permissions in Android 12
https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- legacy for Android 11 or lower -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- legacy for Android 9 or lower -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
And set androidUsesFineLocation when scanning:
// Start scanning
flutterBlue.startScan(timeout: Duration(seconds: 4), androidUsesFineLocation: true);
Android Proguard
Add the following line in your project/android/app/proguard-rules.pro file:
-keep class com.lib.flutter_blue_plus.* { *; }
to avoid seeing the following kind errors in your release builds:
PlatformException(startScan, Field androidScanMode_ for m0.e0 not found. Known fields are
[private int m0.e0.q, private b3.b0$i m0.e0.r, private boolean m0.e0.s, private static final m0.e0 m0.e0.t,
private static volatile b3.a1 m0.e0.u], java.lang.RuntimeException: Field androidScanMode_ for m0.e0 not found
Add permissions for iOS
In the ios/Runner/Info.plist letβs add:
<dict>
...
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to function</string>
...
</dict>
For location permissions on iOS see more at: https://developer.apple.com/documentation/corelocation/requesting_authorization_for_location_services
Add permissions for macOS
Make sure you have granted access to the Bluetooth hardware:
Xcode -> Runners -> Targets -> Runner-> Signing & Capabilities -> App Sandbox -> Hardware -> Enable Bluetooth
Using Ble in App Background
This is an advanced use case. FlutterBluePlus does not support everything. You may have to fork it. PRs are welcome.
iOS
Add the following to your Info.plist
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
</array>
When this key-value pair is included in the appβs Info.plist file, the system wakes up your app to process ble read, write, and subscription events.
To wake up your app even after it is killed by the OS, set the restoreState option to true before starting any FBP work**:
FlutterBluePlus.setOptions(restoreState: true);
Note: Upon being woken up, an app has around 10 seconds to complete a task. Apps that spend too much time executing in the background can be throttled back by the system or killed.
Android
You can try using https://pub.dev/packages/flutter_foreground_task or possibly https://pub.dev/packages/workmanager
API Reference
Note: When functionality is unsupported on a platform, sensible defaults are returned instead of an error.
- π = Stream
- β‘ = Synchronous
- π₯ = Can fail
| Android | iOS | Linux | macOS | Web | Description | |
|---|---|---|---|---|---|---|
| setLogLevel | βοΈ | βοΈ | βοΈ | βοΈ | β | Configure plugin log level |
| setOptions | βοΈ | βοΈ | β | βοΈ | β | Set configurable bluetooth options |
| isSupported | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Checks whether the device supports Bluetooth |
| turnOn π₯ | βοΈ | β | βοΈ | β | β | Turns on the bluetooth adapter |
| turnOff π₯ | βοΈ | β | βοΈ | β | β | Turns off the bluetooth adapter |
| adapterStateNow β‘ | βοΈ | βοΈ | βοΈ | βοΈ | β | Current state of the bluetooth adapter |
| adapterState π | βοΈ | βοΈ | βοΈ | βοΈ | β | Stream of on & off states of the bluetooth adapter |
| startScan π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Starts a scan for Ble devices |
| stopScan π₯ | βοΈ | βοΈ | βοΈ | βοΈ | β | Stop an existing scan for Ble devices |
| onScanResults ππ₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of live scan results |
| scanResults ππ₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of live scan results or previous results |
| lastScanResults β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The most recent scan results |
| isScanning π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of current scanning state |
| isScanningNow β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Is a scan currently running? |
| connectedDevices β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | List of devices connected to your app |
| systemDevices π₯ | βοΈ | βοΈ | βοΈ | βοΈ | β | List of devices connected to the system, even by other apps |
| getPhySupport | βοΈ | β | β | β | β | Get supported bluetooth phy codings |
FlutterBluePlus Events API
| Android | iOS | Linux | macOS | Web | Description | |
|---|---|---|---|---|---|---|
| onConnectionStateChanged π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of connection changes of all devices |
| onMtuChanged π | βοΈ | βοΈ | β | βοΈ | β | Stream of mtu changes of all devices |
| onReadRssi π | βοΈ | βοΈ | βοΈ | βοΈ | β | Stream of rssi reads of all devices |
| onServicesReset π | βοΈ | βοΈ | βοΈ | βοΈ | β | Stream of services resets of all devices |
| onDiscoveredServices π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of services discovered of all devices |
| onCharacteristicReceived π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of characteristic value reads of all devices |
| onCharacteristicWritten π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of characteristic value writes of all devices |
| onDescriptorRead π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of descriptor value reads of all devices |
| onDescriptorWritten π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of descriptor value writes of all devices |
| onBondStateChanged π | βοΈ | β | βοΈ | β | β | Stream of bond state changes of all devices |
| onNameChanged π | β | βοΈ | βοΈ | βοΈ | β | Stream of name changes of all devices |
BluetoothDevice API
| Android | iOS | Linux | macOS | Web | Description | |
|---|---|---|---|---|---|---|
| platformName β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The platform preferred name of the device |
| advName β‘ | βοΈ | βοΈ | β | βοΈ | β | The advertised name of the device found during scanning |
| connect π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Establishes a connection to the device |
| disconnect π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Cancels an active or pending connection to the device |
| isConnected β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Is this device currently connected to your app? |
| isDisconnected β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Is this device currently disconnected from your app? |
| connectionState π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of connection changes for the Bluetooth Device |
| discoverServices π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Discover services |
| servicesList β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The current list of available services |
| onServicesReset π | βοΈ | βοΈ | βοΈ | βοΈ | β | The services changed & must be rediscovered |
| mtu π | βοΈ | βοΈ | β | βοΈ | β | Stream of current mtu value + changes |
| mtuNow β‘ | βοΈ | βοΈ | β | βοΈ | β | The current mtu value |
| readRssi π₯ | βοΈ | βοΈ | βοΈ | βοΈ | β | Read RSSI from a connected device |
| requestMtu π₯ | βοΈ | β | β | β | β | Request to change the MTU for the device |
| requestConnectionPriority π₯ | βοΈ | β | β | β | β | Request to update a high priority, low latency connection |
| bondState π | βοΈ | β | βοΈ | β | β | Stream of device bond state. Can be useful on Android |
| createBond π₯ | βοΈ | β | βοΈ | β | β | Force a system pairing dialogue to show, if needed |
| removeBond | βοΈ | β | βοΈ | β | β | Remove Bluetooth Bond of device |
| setPreferredPhy | βοΈ | β | β | β | β | Set preferred RX and TX phy for connection and phy options |
| clearGattCache | βοΈ | β | β | β | β | Clear android cache of service discovery results |
BluetoothCharacteristic API
| Android | iOS | Linux | macOS | Web | Description | |
|---|---|---|---|---|---|---|
| uuid β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The uuid of characteristic |
| read π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Retrieves the value of the characteristic |
| write π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Writes the value of the characteristic |
| setNotifyValue π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Sets notifications or indications on the characteristic |
| isNotifying β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Are notifications or indications currently enabled |
| onValueReceived π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of characteristic value updates received from the device |
| lastValue β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The most recent value of the characteristic |
| lastValueStream π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of onValueReceived + writes |
BluetoothDescriptor API
| Android | iOS | Linux | macOS | Web | Description | |
|---|---|---|---|---|---|---|
| uuid β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The uuid of descriptor |
| read π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Retrieves the value of the descriptor |
| write π₯ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Writes the value of the descriptor |
| onValueReceived π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of descriptor value reads & writes |
| lastValue β‘ | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | The most recent value of the descriptor |
| lastValueStream π | βοΈ | βοΈ | βοΈ | βοΈ | βοΈ | Stream of onValueReceived + writes |
Debugging
The easiest way to debug issues in FlutterBluePlus is to make your own local copy.
cd /user/downloads
git clone https://github.com/boskokg/flutter_blue_plus.git
then in pubspec.yaml add the repo by path:
flutter_blue_plus:
path: /user/downloads/flutter_blue_plus
Now you can edit the FlutterBluePlus code yourself.
Common Problems
Many common problems are easily solved.
Adapter:
- bluetooth must be turned on
- adapterState is not 'on' but my Bluetooth is on
- adapterState is called multiple times
Scanning:
Connecting:
- Connection fails
- connectionState is called multiple times
- remoteId is different on Android vs iOS
- iOS: "[Error] The connection has timed out unexpectedly."
Reading & Writing:
Subscriptions:
- onValueReceived is never called (or lastValueStream)
- onValueReceived data is split up (or lastValueStream)
- onValueReceived is called with duplicate data (or lastValueStream)
Android Errors:
Flutter Errors:
"bluetooth must be turned on"
You need to wait for the bluetooth adapter to fully turn on.
await FlutterBluePlus.adapterState.where((state) => state == BluetoothAdapterState.on).first;
You can also use FlutterBluePlus.adapterState.listen(...). See Usage.
adapterState is not 'on' but my Bluetooth is on
For iOS:
adapterState always starts as unknown. You need to wait longer for the service to initialize. As simple as:
if (await FlutterBluePlus.adapterState.first == BluetoothAdapterState.unknown) {
await Future.delayed(const Duration(seconds: 1));
}
If adapterState is unavailable, you must add access to Bluetooth Hardware in the app's Xcode settings. See Getting Started.
For Android:
Check that your device supports Bluetooth & has permissions.
adapterState is called multiple times
You are forgetting to cancel the original FlutterBluePlus.adapterState.listen resulting in multiple listeners.
// tip: using ??= makes it easy to only make new listener when currently null
final subscription ??= FlutterBluePlus.adapterState.listen((value) {
// ...
});
// also, make sure you cancel the subscription when done!
subscription.cancel()
Scanning does not find my device
1. you're using an emulator
Use a physical device.
2. try using another ble scanner app
- iOS: nRF Connect
- Android: BLE Scanner
Install a BLE scanner app on your phone. Can it find your device?
3. your device uses bluetooth classic, not BLE.
Headphones, speakers, keyboards, mice, gamepads, & printers all use Bluetooth Classic.
These devices may be found in System Settings, but they cannot be connected to by FlutterBluePlus. FlutterBluePlus only supports Bluetooth Low Energy.
4. your device stopped advertising.
- you might need to reboot your device
- you might need to put your device in "discovery mode"
- your phone may have already connected automatically
- another app may have already connected to your device
- another phone may have already connected to your device
Try looking through system devices:
// search system devices. i.e. any device connected to by *any* app
List<BluetoothDevice> system = await FlutterBluePlus.systemDevices;
for (var d in system) {
print('${r.device.platformName} already connected to! ${r.device.remoteId}');
if (d.platformName == "myBleDevice") {
await r.connect(); // must connect our app
}
}
5. your scan filters are wrong.
- try removing all scan filters
- for
withServicesto work, your device must actively advertise the serviceUUIDs it supports
6. Android: you're calling startScan too often
On Adroid you can only call startScan 5 times per 30 second period. This is a platform restriction.
7. Android: make sure location services are enabled
Android requires location services to allow bluetooth scanning.
Scanned device never goes away
This is expected.
You must set the removeIfGone scan option if you want the device to go away when no longer available.
iBeacons Not Showing
iOS:
iOS does not support iBeacons using CoreBluetooth. You must find a plugin meant for CoreLocation.
Android:
- you need to enable location permissions, see Getting Started
- you must pass
androidUsesFineLocation:trueto thestartScanmethod.
Connection fails
1. Your ble device may be low battery
Bluetooth can become erratic when your peripheral device is low on battery.
2. Your ble device may have refused the connection or have a bug
Connection is a two-way process. Your ble device may be misconfigured.
3. You may be on the edge of the Bluetooth range.
The signal is too weak, or there are a lot of devices causing radio interference.
4. Some phones have an issue connecting while scanning.
The Huawei P8 Lite is one of the reported phones to have this issue. Try stopping your scanner before connecting.
5. Try restarting your phone
Bluetooth is a complicated system service, and can enter a bad state.
connectionState is called multiple times
You are forgetting to cancel the original device.connectionState.listen resulting in multiple listeners.
// tip: using ??= makes it easy to only make new listener when currently null
final subscription ??= FlutterBluePlus.device.connectionState.listen((value) {
// ...
});
// also, make sure you cancel the subscription when done!
subscription.cancel()
The remoteId is different on Android versus iOS & macOS
This is expected. There is no way to avoid it.
For privacy, iOS & macOS use a randomly generated uuid. This uuid will periodically change.
e.g. 6920a902-ba0e-4a13-a35f-6bc91161c517
Android uses the mac address of the bluetooth device. It never changes.
e.g. 05:A4:22:31:F7:ED
iOS: "[Error] The connection has timed out unexpectedly."
You can google this error. It is a common iOS ble error code.
It means your device stopped working. FlutterBluePlus cannot fix it.
List of Bluetooth GATT Errors
These GATT error codes are part of the BLE Specification.
These are responses from your ble device because you are sending an invalid request.
FlutterBluePlus cannot fix these errors. You are doing something wrong & your device is responding with an error.
GATT errors as they appear on iOS:
apple-code: 1 | The handle is invalid.
apple-code: 2 | Reading is not permitted.
apple-code: 3 | Writing is not permitted.
apple-code: 4 | The command is invalid.
apple-code: 6 | The request is not supported.
apple-code: 7 | The offset is invalid.
apple-code: 8 | Authorization is insufficient.
apple-code: 9 | The prepare queue is full.
apple-code: 10 | The attribute could not be found.
apple-code: 11 | The attribute is not long.
apple-code: 12 | The encryption key size is insufficient.
apple-code: 13 | The value's length is invalid.
apple-code: 14 | Unlikely error.
apple-code: 15 | Encryption is insufficient.
apple-code: 16 | The group type is unsupported.
apple-code: 17 | Resources are insufficient.
apple-code: 18 | Unknown ATT error.
GATT errors as they appear on Android:
android-code: 1 | GATT_INVALID_HANDLE
android-code: 2 | GATT_READ_NOT_PERMITTED
android-code: 3 | GATT_WRITE_NOT_PERMITTED
android-code: 4 | GATT_INVALID_PDU
android-code: 5 | GATT_INSUFFICIENT_AUTHENTICATION
android-code: 6 | GATT_REQUEST_NOT_SUPPORTED
android-code: 7 | GATT_INVALID_OFFSET
android-code: 8 | GATT_INSUFFICIENT_AUTHORIZATION
android-code: 9 | GATT_PREPARE_QUEUE_FULL
android-code: 10 | GATT_ATTR_NOT_FOUND
android-code: 11 | GATT_ATTR_NOT_LONG
android-code: 12 | GATT_INSUFFICIENT_KEY_SIZE
android-code: 13 | GATT_INVALID_ATTRIBUTE_LENGTH
android-code: 14 | GATT_UNLIKELY
android-code: 15 | GATT_INSUFFICIENT_ENCRYPTION
android-code: 16 | GATT_UNSUPPORTED_GROUP
android-code: 17 | GATT_INSUFFICIENT_RESOURCES
Descriptions:
1 | Invalid Handle | The attribute handle given was not valid on this server.
2 | Read Not Permitted | The attribute cannot be read.
3 | Write Not Permitted | The attribute cannot be written.
4 | Invalid PDU | The attribute PDU was invalid.
5 | Insufficient Authentication | The attribute requires authentication before it can be read or written.
6 | Request Not Supported | Attribute server does not support the request received from the client.
7 | Invalid Offset | Offset specified was past the end of the attribute.
8 | Insufficient Authorization | The attribute requires an authorization before it can be read or written.
9 | Prepare Queue Full | Too many prepare writes have been queued.
10 | Attribute Not Found | No attribute found within the given attribute handle range.
11 | Attribute Not Long | The attribute cannot be read or written using the Read Blob or Write Blob requests.
12 | Insufficient Key Size | The Encryption Key Size used for encrypting this link is insufficient.
13 | Invalid Attribute Value Length | The attribute value length is invalid for the operation.
14 | Unlikely Error | The request has encountered an unlikely error and cannot be completed.
15 | Insufficient Encryption | The attribute requires encryption before it can be read or written.
16 | Unsupported Group Type | The attribute type is not a supported grouping as defined by a higher layer.
17 | Insufficient Resources | Insufficient Resources to complete the request.
characteristic write fails
First, check the List of Bluetooth GATT Errors for your error.
1. your bluetooth device turned off, or is out of range
If your device turns off or crashes during a write, it will cause a failure.
2. Your Bluetooth device has bugs
Maybe your device crashed, or is not sending a response due to software bugs.
3. there is radio interference
Bluetooth is wireless and will not always work.
Characteristic read fails
First, check the List of Bluetooth GATT Errors for your error.
1. your bluetooth device turned off, or is out of range
If your device turns off or crashes during a read, it will cause a failure.
2. Your Bluetooth device has bugs
Maybe your device crashed, or is not sending a response due to software bugs.
3. there is radio interference
Bluetooth is wireless and will not always work.
onValueReceived is never called (or lastValueStream)
1. you are not calling the right function
lastValueStream will receive data for chr.read() & chr.write() & chr.setNotifyValue(true)
onValueReceived will receive data for chr.read() & chr.setNotifyValue(true)
2. your device has nothing to send
If you are using chr.setNotifyValue(true), your device chooses when to send data.
Try interacting with your device to get it to send new data.
3. your device has bugs
Try rebooting your ble device.
Some ble devices have buggy software and stop sending data
onValueReceived data is split up (or lastValueStream)
Verify that the mtu is large enough to hold your message.
device.mtu
If it still happens, it is a problem with your peripheral device.
onValueReceived is called with duplicate data (or lastValueStream)
You are probably forgetting to cancel the original chr.onValueReceived.listen resulting in multiple listens.
The easiest solution is to use device.cancelWhenDisconnected(subscription) to cancel device subscriptions.
final subscription = chr.onValueReceived.listen((value) {
// ...
});
// make sure you have this line!
device.cancelWhenDisconnected(subscription);
await characteristic.setNotifyValue(true);
ANDROID_SPECIFIC_ERROR
There is no 100% solution.
FBP already has mitigations for this error, but Android will still fail with this code randomly.
The recommended solution is to catch the error, and retry.
android pairing popup appears twice
This is a bug in android itself.
You can call createBond() yourself just after connecting and this will resolve the issue.
MissingPluginException(No implementation found for method XXXX ...)
If you just added flutter_blue_plus to your pubspec.yaml, a hot reload / hot restart is not enough.
You need to fully stop your app and run again so that the native plugins are loaded.
Also try flutter clean.
Changelog
1.36.8
- [Fix] Dart:
isNotifyingwas broken (regression 1.36.2)
1.36.7
- [Fix] iOS/macOS/Android:
setOptions&setLogLevelshould not invokeflutterRestart(regression 1.35.0) - [Fix] Linux:
discoverServices: wait forservicesResolvedto avoid partial results (#1265) - [Fix] Linux:
setNotifyValue: return false (no CCCD) to prevent hang (#1264) - [Fix] Dart: undo "clear
servicesListafter disconnection" (regression 1.35.11)
1.36.6
- [Fix] fix android compile error (regression 1.36.2)
1.36.5
- [Fix] fix federated dependencies (regression 1.36.2)
1.36.4
- [Fix] fix compile error due to out of date platform interface (regression 1.36.2)
1.36.3
- [Fix] internal cleanup, no user facing changes
1.36.2
- [Fix]
lastValuewas broken (regression 1.35.6)
1.36.1
- [Fix]
onValueReceivedno longer emits data after reconnection #1262 (regression 1.35.6)
1.36.0
- [Fix] characteristic not found, due to
instanceIdbug (regression 1.35.6)
1.35.12
- [Improve] Dart: add
pubspec_overrides.yamlfor easier local development
1.35.11
- [Fix] Android: fix main thread crash due to
waitIfBonding(regression 1.35.8) - [Fix] Dart: clear
servicesListafter disconnection
1.35.10
- [Improve] Android: use user provided
compileSdkVersion
1.35.9
- [Fix] Android: compile error, due to missing
toString(regression 1.35.8)
1.35.8
- [Fix] Android: HotRestart must also cancel autoconnect
- [Fix] Android:
waitIfBondingwas not waiting - [Fix] iOS/macOS: fix warnings in
resetInstanceIds(regression 1.35.6) - [Improve] Android: show nicer
ensurePermissionserror for no Context
1.35.7
- [Fix] pubspec.yaml was broken, due to invalid constraints in web package (regression 1.35.6)
1.35.6
- [Feature] Support multiple characteristics with the same UUID
- [Fix] iOS/macOS: fix crash on incorrect PIN
- [Fix] Android: fix
onServicesReset - [Fix] iOS/macOS: fix integer conversion warnings
- [Improve] Android: more HCI status codes
1.35.5
- [Feature] Android: added
androidCheckLocationServicestostartScan(#1199)
1.35.4
- [Feature] Android: check if location services are enabled before doing scan (#1167)
- [Improve] better
Guidequals operator (#1169) - [Fix] Android:
webOptionalServicesbroke scanning on android (regression 1.35.4) - [Fix] Android: turnOn was not checking response (#1166) (regression 1.35.0)
- [Fix] Android: multiple MSD in advertisement is wrong on Android
- [Fix] Android: use Bluetooth request code less than 2^16 to prevent permissions error
- [Fix] Linux: exception when adapters is empty (#1162)
- [Fix] Web:
getAdapterStateanddiscoverServicesfixes - [Fix] Web: don't wait for CCCD write for
setNotifyValue(#1153) - [Refactor] Performance: use bytes instead of hex for platform communication (#1130)
1.35.3
- [Feature] Web: support for web optional services (#1124)
- [Feature] Android: option to provide pairing PIN to
createBond(#1119)
1.35.2
- [Fix] add back log color (regression 1.35.0)
- [Fix] resolve the Dart analyzer issues (regression 1.35.0)
1.35.1
- [Fix] Bluetooth characteristic set notify value (regression 1.35.0)
- [Fix] Bluetooth device create bond (regression 1.35.0)
- [Fix] Bluetooth device remove bond (regression 1.35.0)
- [Fix] Bluetooth device connect (regression 1.35.0)
- [Fix] Bluetooth device disconnect (regression 1.35.0)
- [Fix] Bluetooth adapter turn on (regression 1.35.0)
- [Fix] Bluetooth adapter turn off (regression 1.35.0)
1.35.0
This release adds support for Web, Linux, and the Platform Interface.
- [Feature] add platform interface
1.34.5
- [Feature] add
FlutterBluePlus.logsto get access to FBP logs
1.34.4
- [Improve] improve error message when secondary service is not found
1.34.3
- [Fix]
startScanwas not propogating errors (regression 1.31.7)
1.34.2
- [Fix] characteristic not found (regression 1.34.0)
1.34.1
- [Fix] Android:
SCAN_FAILED_ALREADY_STARTEDcould sometimes occur after bluetooth restart
1.34.0
- [Feature] support
includedServices, aka primary/secondary services - [Fix] Android:
withServiceDatascan filter was not working (regression in 1.28.3)
1.33.6
- [Feature] verbose logs: make function results easier to see
1.33.5
- [Fix] iOS: crash caused by 1-byte advertisements (#1022)
1.33.4
- [Fix] Android: null deref when getting permissions (regression 1.33.3)
1.33.3
- [Fix] Android: asking permission would not work until app restart (regression 1.32.13)
1.33.2
- [Fix] Android: compile bug in 1.33.1
1.33.1
- [Fix] Android: compile bug in 1.33.0
1.33.0
- [BREAKING CHANGE] iOS 18 compatibility:
systemDevicesnow requires UUID argument - [Fix] Android: characteristic READ error was not being passed to dart
1.32.13
- [Feature] iOS: add support for State Preservation
- [Improve] Android: ask for both scan permissions at the same time
1.32.12
- [Fix] Android: further improve
disconnect(queue:false)reliability - [Deprecate] deprecate BluetoothDevice.fromProto(...)
1.32.11
- [Improve] Android: perf: speed up
bytesToHex
1.32.10
- [Fix] Android: calling
disconnect(queue:false)may sometimes silently fail
1.32.9
- [Feature] Android: add legacy scan option
1.32.8
- [Fix] iOS: was not updating
lastValueStreamifwithoutResponse:true
1.32.7
- [Fix] android: last byte was cutoff for msd of same manufactuerId (regression 1.32.5)
1.32.6
- [Fix] calling
startScanmultiple times in a row would fail
1.32.5
- [Fix] android: support multiple MSD with the same manufacturer ID
1.32.4
- [Improve] revert 1.32.3 (i.e. go back to 1.32.1 behavior)
- [Fix] fix
SCAN_FAILED_ALREADY_STARTEDon android after adapter is turnedoffthenon
1.32.3
- [Improve] allow calling
stopScaneven if not currently scanning. (revert 1.32.1)
1.32.2
- [Improve] iOS: fix warning about implicit conversion for showPowerAlert
1.32.1
- [Fix] Android: scan failure were not being pushed to onError
- [Improve] only
stopScanif currently scanning. prevents 'could not find callback wrapper' log on Android
1.32.0
This realease has a very slight behavior change for adapterState & connectionState
- [Improve] update
adapterStatestream beforeconnectionStatestreams. Simplifies internal autoconnect code.
1.31.19
- [Improve] autoconnect: catch & print errors when autoconnect fails
1.31.18
- [Feature] add
setOptionsfunction. Used to configure power alert on iOS
1.31.17
- [Fix] android: autoconnect could enter disconnect / connection loop
- [Fix] android: calling
disconnectshould always disable autoconnect, even if already disconnected
1.31.16
- [Fix] forgot to push to mtu stream after disconnection
1.31.15
- [Feature] support advertising
appearanceon Android
1.31.14
- [Fix] autoconnect could not disconnect if there are multiple devices
1.31.13
- [Improve] android: use name
LINK_SUPERVISION_TIMEOUTinstead ofCONNECTION_TIMEOUT
1.31.12
- [Improve] improve reliability of autoconnect on android
1.31.11
- [Feature] add convenience function to get raw
msddata in advertisement
1.31.10
- [Fix] type 'DeviceIdentifier' is not a subtype of type 'String' (regression 1.31.9)
1.31.9
- [Feature] add
cancelAfterDisconnectiondelayedoption forconnectionStatestreams - [Feature] add
device.isDisconnected
1.31.8
- [Fix] stream asserts when calling
startScantwice quickly
1.31.7
- [Fix]
cancelWhenScanCompletemust handle error cases
1.31.6
- [Feature] add
cancelWhenScanCompleteconvenience function
1.31.5
- [Improve] Updated README & Example app
1.31.4
- [Fix] iOS: mtu and auto connect are incompatible
1.31.3
- [Fix]
adapterState.first&connectionState.firstdont work (regression 1.30.7)
1.31.2
- [Fix] Gradle 7 (Flutter 2) would not build (regression 1.7.6)
1.31.1
- [Fix] iOS: scan filters were doing nothing (regression 1.31.0)
1.31.0
This release adds support for multiple scan filters at the same time.
- [Feature] iOS: support multiple scan filters at the same time
1.30.9
- [Improve] assert: fbp only supprts a single
scanfilter at a time
1.30.8
- [Improve] android: discoverServices: add
subscribeToServicesChangedoption
1.30.7
- [Fix]
autoConnectnot always working (bug in 1.30.0) - [Fix] perf:
NewStreamWithInitialValuewas not closing its streams (regression 1.17.2) - [Feature] add
device.isAutoConnectEnabled
1.30.6
- [Improve] ios log more detail
- [Feature] add
adapterStateNowgetter
1.30.5
- [Fix] iOS build error (regression 1.30.4)
- [Fix] android
autoConnectwas broken (regression 1.30.1)
1.30.4
- [Fix] Perf: must close
adapterState,bondState&scanResultsBufferStreams - [Improve] iOS: set
kCBConnectOptionEnableAutoReconnectoption - [Improve] requestMtu: add
predelayargument - [Example] only call
setStateif mounted
1.30.3
- [Fix] android: connect crashes (regression in 1.30.0)
1.30.2
- [Improve] auto connect: assert that mtu is null in
connect
1.30.1
- [Feature] auto connect: remove
setAutoConnectfunction added in 1.30.0 and go back to usingconnect:autoConnectparameter
1.30.0
This release greatly improves autoconnect support on Android, and adds iOS support.
- [Improve] android: auto connect is no longer canceled when bluetooth is turned off
- [Fix] android:
deadObjectExceptionswhen bluetooth is turned off
1.29.13
- [Improve] android: add delay before
requestMtuis called to work arounddiscoverServicestimeout
1.29.12
- [Fix] android:
CALLBACK_TYPE_FIRST_MATCHcauses scanning issues (regression in 1.27.0) - [Fix] android:
withKeywordswasn't filtering out adverts that have no scan record (bug in original feature)
1.29.11
- [Fix] android:
remoteIdwas wrong (regression in 1.29.10)
1.29.10
- [Fix] android:
isNotifyingwas not updated (regression in 1.28.5) - [Improve] accidentally logging 'canceling connection in progress' every time
1.29.9
- No changes. This version was accidentally skipped.
1.29.8
- [Fix] android: crash due to wrong type cast (regression in 1.29.7)
1.29.7
- [Fix] scan errors should be pushed to
scanResultsstream (bug in originalflutter_blue) - [Fix] android: scan: when
continuousUpdatesisfalse, don't filter non-duplicate adverts (bug in original feature) - [Improve] make sure
continuousDivisoronly applies whencontinuousUpdatesis true
1.29.6
- [Improve] default
continuousDivisorshould be 1 - [Improve]
continuousDivisorshould be applied after scan filters
1.29.5
- [Fix] iOS: 'service not found' if service supports short uuid (regression 1.28.5)
- [Improve] android: handle
turnOnuser rejected
1.29.4
- [Fix] characteristics with same UUID could return wrong
propertiesordescriptors(regression in 1.20.4)
1.29.1 to 1.29.3
- [Improve] more refinements to
onScanResults
1.29.0
- [Breaking Change]
scanResults: do not clear results afterstopScan. If you want results cleared useonScanResultsinstead. - [Add]
lastScanResultsto synchronously get the most recent results
1.28.14
- [Fix]
setAdvertisingDataTypecrash on android 10 and below (regression in 1.28.10)
1.28.13
- [Fix]
isNotifyingwas not set to false on disconnection (regression in 1.28.9)
1.28.12
- [Fix] crash if
rssiwas zero on android (regression in 1.27.2)
1.28.11
- [Rename]
giud.uuid->guid.str&guid.uuid128->guid.str128 - [Add] connect:
timeoutargument is now optional. infinite timeout is possible on iOS
1.28.10
- [Perf] android: filter out devices without names if
scan.withKeywordsis set - [Fix] calling scan multiple times would breifly push
isScanning=false - [Improve]
servicesList: return empty instead of null
1.28.9
- [Improve] to make FBP easier to use, never clear
knownServices
1.28.8
- [Fix] android: GUID issues related to scanning (regression in 1.28.3)
1.28.7
- [Fix] android: GUID starting with 0000 were misinterpretted (regression in 1.28.5)
1.28.6
- [Improve] simplify api: clear
knownServiceson reconnection instead of disconnection - [Improve] dont clear
bondStatecache when device is disconnected. unecessary.
1.28.5
- [Internal] use short UUID where possible
1.28.4
- [Fix] guid: uuid was returning 0000 for 16 bit uuid (regression in 1.28.3)
- [Guid]
guid.uuidshould return lowercase
1.28.3
- [Improve] guid: add
uuidshort representation
1.28.2
- [Improve] add length checks to
MsdFilter&ServiceDataFilter - [Improve] guid: more consistent handling of 16, 32, vs 128 bit guids
1.28.1
- [Feature] scanning: add
withServiceDatafilter - [Feature] scanning: add
withMsdfilter
1.28.0
- [Breaking Change]
guid.toString()now returns 16-bit short uuid when possible - [Breaking Change] return
GUIDs foradvertisingData.serviceUuids&advertisingData.serviceDatainstead of String - [Guid] add support for 16-bit and 32-bit uuids
- [Fix] android: advertised UUIDs were 128-bit instead of the actual length (regression in 1.14.17)
1.27.6
- [Improve] add more checks for bluetooth being off
1.27.5
- [Fix] android: typo compile error (regression in 1.27.3)
1.27.4
- [Fix] accidentally changed
advertisementData.localNameto nullable (regression in 1.27.3)
1.27.3
- [Perf] scanning: add
continuousDivisoroption to reduce platform channel & main-thread usage
1.27.2
- [Perf] scanning: only send advertisment keys over platform channel when they exist
- [Rename]
advertisementData.localName->advertisementData.advName
1.27.1
- [Add] android: add
forceIndicationsoption tosetNotifyValue
1.27.0
This release improves the default scanning behavior.
- [Breaking Change] scanning: make
continousUpdatesfalse by default - it is not typically needed & hurts perf. If your app usesstartScan.removeIfGone, or your app continually checks the value ofscanResult.timestamporscanResult.rssi, then you will need to explicitly setcontinousUpdatesto true.
1.26.6
- [Fix] android: scanning would not work if
continuousUpdateswas false (regression in 1.26.5)
1.26.5
- [Add] scanning:
withRemoteIds,withNames,withKeywordsfilters - [Add] scanning: expose
androidScanModeagain - [Add] scanning:
continuousUpdatesoption replaces formerallowDuplicatesoption
1.26.4
- [Add]
cancelWhenDisconnected: option to cancel on next disconnection
1.26.3
- [Add]
events.onReadRssi - [Add]
events.onCharacteristicWritten - [Add]
events.onDescriptorWritten
1.26.2
- [Fix] android: close gatt after canceling an in-progress connnection (regression in 1.26.1)
- [Improve] android: wait until bonding completes for better reliability
1.26.1
- [Feature] add support for canceling an in progress connection using
device.disconnect - [Fix] connection timeouts did not actually cancel the connection attempt (regression in 1.5.0)
- [Fix] android: update
isScanningwhenonDetachedFromEngineis called (bug in originalflutter_blue)
1.22.1 to 1.26.0
These releases changed multiple things but then changed them back. For brevity, here are the actual changes:
- [Behavior Change] android: listen to Services Changed characteristic to match iOS behavior
- [Fix] android: stop scanning when detached from engine (bug in original
flutter_blue) - [Add]
device.advNamereturns the name found during scanning - [Add]
device.mtuNowsynchronously gets the current mtu value - [Add]
events.onDiscoveredServicesstream - [Add] events api: add accessors for errors
- [Rename] events api: most functions & classes were renamed for consistency
- [Rename]
device.onServicesChanged->device.onServicesReset - [Remove]
device.onNameChanged, in favor of only exposingevents.onNameChanged
1.22.0
This release makes mtu behavior more similar on android & iOS.
- [Breaking Change] android: request mtu of 512 by default.
1.21.0
This release greatly increases reliability on android & ios.
- [Improve] only allow a single ble operation at a time.
1.20.8
- [Fix] iOS: connect: return error for invalid
remoteId(bug in originalflutter_blue) - [Improve] iOS: log warning if CCCD is not found, like we do on android
1.20.7
- [Fix] events API was not accessible through
FlutterBluePlus.events
1.20.6
- [Add]
FlutterBluePlus.events.mtu
1.20.5
- [Add]
FlutterBluePlus.events.onNameChanged - [Add]
FlutterBluePlus.events.onServicesChanged
1.20.4
- [Rename]
FlutterBluePlus.connectionEvents->FlutterBluePlus.events.connectionState - [Add]
FlutterBluePlus.events.onCharacteristicReceived - [Add]
FlutterBluePlus.events.onDescriptorRead - [Add]
FlutterBluePlus.events.bondState
1.20.3
- [Add]
FlutterBluePlus.connectionEvents, a stream of all connection & disconnected events - [Add]
FlutterBluePlus.connectedDevices, to get currently connected devices - [Add]
device.isConnected, convenience accessor
1.20.2
- [Fix] cannot retrieve platform name from
bondedDevices(regression) - [Fix]
stopScan: should clear results after platform method has been called (bug in originalflutter_blue)
1.20.1
- [Remove]
FlutterBluePlus.connectedDevices. This API needs more thought.
1.20.0
This release renames connectedSystemDevices.
- [Rename]
connectedSystemDevices->systemDevices, because they must be re-connected by your app
1.19.2
- [Add] new method
device.cancelWhenDisconnected(subscription)
1.19.1
- [Add] new method
FlutterBluePlus.connectedDevices
1.19.0
This release reverts most of the breaking changes made in 1.18.0.
- [Revert] most breaking changes made to
bondStatestream in 1.18.0 - [Unchanged] bond lost/failed are replaced by
prevBondState - [Add] method
device.prevBondState - [Fix] android:
adapterNamemust request permission (bug in originalflutter_blue)
1.18.3
- [Refactor]
bondState: finish refactor started in 1.18.0
1.18.2
- [Fix]
bondState: must explicitly check for nullprevState(regression in 1.18.0)
1.18.1
- [Fix]
bondState: handle nullprevState(regression in 1.18.0)
1.18.0
This release improves bondState stream
- [Breaking Change]
bondState: directly exposeprevBondinstead of lost/failed flags
1.17.6
- [Fix]
scanResults: clear scan results onstopScan(regression in 1.16.8)
1.17.5
- [Example] accidentally left
performanceOverlayenabled (regression in 1.17.4)
1.17.4
- [Example] remove
PermissionHandlerdependency. It is no longer needed. - [Example] ScanScreen: use
ListViewinstead ofSingleChildScrollView
1.17.3
- [Fix] android:
turnOnthrows exception if permission denied (bug in originalflutter_blue)
1.17.2
This bug affected mtu, lastValueStream, adapterState, & bondState.
- [Fix]
newStreamWithInitialValuewas not emitting initial value. (regression in 1.16.6)
1.17.1
- [Fix] timeout when
connectis called when adapter is off (bug in originalflutter_blue) - [Fix] android: was not calling
disconnectcallback when adapter turned off (bug in originalflutter_blue) - [Fix] android:
connectableflag was not working (regression in 1.7.0) - [Improve] do not re-get
adapterStatewhen we already have it
1.17.0
This release improves lastValue & lastValueStream.
- [Breaking Change/Fix] should update
lastValue&lastValueStreamwhenwriteis called - [Feature] Android: support
onNameChanged&onServicesChangedcharacteristics - [Fix] iOS:
discoverServicescrash "[_NSInlineData intValue]: unrecognized selector sent to instance" (bug in originalflutter_blue) - [Fix] iOS:
descriptor.writewould timeout or not work (regression somewhere around ~1.7.0) - [Fix]
isNotifyingwas not updated bysetNotifyValue(false)(regression somewhere around ~1.9.0)
1.16.12
- [Fix] Android:
onValueReceivedwas not working on Android 12 & lower (regression in 1.16.3)
1.16.11
- [Fix] Android:
onCharacteristicReceivednot being called (regression in 1.16.3)
1.16.10
- [Fix] BluetoothDevice: don't wait for timeout if device becomes disconnected (bug in original
flutter_blue)
1.16.9
- [Example] cleaned up Characteristic tile code
1.16.8
- [Fix]
scanResults&isScanningstreams were not re-emitting their current value on listen (regression in 1.5.0) - [Example]
discoverServices: stay on screen after diconnection - [Example] simplified
connectingOrDisconnectingcode - [Example] organize into 'screens' and 'widgets' folders
1.16.7
- [Rename]
isAvailable->isSupported
1.16.6
- [Example] Refactor: hugely refactored to use stateful widgets
- [Example] Fix: stream already listened to error
- [Improve]
connectionState&mtu: use broadcast stream
1.16.5
- [Fix] iOS: iOS Unhandled Exception: type 'int' is not a subtype of type 'bool' (regression in 1.16.3)
- [Improve] android: prepend logs with '[FBP]'
- [Java] rename
com.boskokg.flutter_blue_plus->com.lib.flutter_blue_plusto be more generic
1.16.4
- [Fix]
setLogLevelwould be ignored due to being called twice (regression in 1.10.0) - [Improve] android: use log level consistently
- [Improve] iOS: use log level macro
1.16.3
- [Fix] Android:
setNotifywould timeout if CCCD descriptor does not exist (regression in 1.5.0) - [Android] fix deprecations
- [Improve]
removeIfGone: only push to scanResults when list changes
1.16.2
- [Fix] platform check in
onNameChanged&onServicesChangedwas incorrect
1.16.1
- [Add] iOS: add support for
onServicesChanged&onNameChanged
1.16.0
This release simplifies BluetoothDevice construction.
- [Breaking Change] remove
BluetoothDevice.type&BluetoothDevice.localNamefrom constructor for simplicity - [Breaking Change] remove
servicesStream&isDiscoveringServicesdeprecated functions - [Rename]
localName->platformNameto reflect platform specific behavior - [Fix]
setNotifyValuemust takedescWritemutex (bug in originalflutter_blue) - [Fix]
localNamewas broken when usingconnectedSystemDevices(regression in 1.15.10) - [Add] Android:
getPhySupport
1.15.10
- [Fix] iOS:
localNamedoes not match Android (bug in originalflutter_blue) - [Fix] flutterRestart: error was thrown if device did not have bluetooth adapter (regression in 1.14.19)
1.15.9
- [Fix] iOS: adapter turnOff: edge case when adapter is turned off while scanning (bug in original
flutter_blue) - [Fix] iOS: adapter turnOff: disconnect handlers not firing when adapter turned off (bug in original
flutter_blue) - [Fix] iOS: adapter turnOff: API MISUSE when adapter is turned off (bug in original
flutter_blue) - [Cleanup] Hot Restart: use separate
connectedCountmethod for clarity
1.15.8
- [Fix] if any platform exception happens, fbp will deadlock (regression in 1.14.20)
1.15.7
- [Fix] android: turning bluetooth off would not fully disconnect devices (regression in 1.14.19)
1.15.6
- [Fix] iOS: turning bluetooth off would not fully disconnect devices (regression in 1.14.19)
- [Readme] add v1.15.0 migration guides
1.15.5
- [Fix]
firstWhereOrNullconflict (regression in 1.15.0)
1.15.4
- [Fix] some typos in disconnect exceptions (regression in 1.15.3)
1.15.3
- [Improve] prefer dart exceptions over platform exceptions when device is disconnected
1.15.2
- [Fix]
stopScanwas not awaiting for invokeMethod (regression in 1.15.0)
1.15.1
- [Fix]
FlutterBluePlus.scanResultsshould always return list copy to avoid iteration exceptions (regression in 1.15.0)
1.15.0
Scanning API Changes
Overview:
- [Refactor] simplify scanning api
- [Feature] add
removeIfGoneoption tostartScan
Breaking Changes & Improvements:
- [Simplify] removed
FlutterBluePlus.scan. UseFlutterBluePlus.scartScan(oneByOne: true)instead. - [Simplify] removed
allowDuplicatesoption forscartScan. It is not supported on android. We always filter duplicates anyway. - [Simplify] removed
macAddressesoption forscartScan. It was not supported on iOS, and is overall not very useful. - [Simplify]
startScannow returnsFuture<void>instead ofFuture<List<ScanResult>>. It was redundant and confusing. - [Improve] if you
await startScanit will complete once the scan starts, instead of when it ends - [Improve] if you call
startScantwice, it will cancel the previous scan, instead of throwing an exception
1.14.24
- [Fix] Android:
setNotifyValue: "(code: 5) notifications were not updated" (regression in 1.14.23) - [Fix] Hot Restart: stop scanning when hot restarting (bug in original
flutter_blue)
1.14.23
- [Fix]
setNotifyValue& others must be cleared after disconnection (regression in 1.14.21)
1.14.22
- [Fix] Android: Hot Restart: could get stuck in infinite loop (regression in 1.14.19)
1.14.21
- [Refactor] dart: store
lastValueat global level so Desc & Chr classes are fully immutable
1.14.20
- [Fix] iOS: Hot Restart: could get stuck in infinite loop (regression in 1.14.19)
1.14.19
- [Fix] Hot Restart: close all connections when dart vm is restarted (bug in original
flutter_blue)
1.14.18
- [Fix] Android: crash
uuid128null deref (regression in 1.14.17)
1.14.17
- [Fix] Android: shortUUID: characteristic not found (bug in original
flutter_blue)
1.14.16
- [Fix] macOS: lower required version to 10.11 (equivalent to iOS 9.0)
1.14.15
- [Rename]
allowSplits->allowLongWrite
1.14.14
- [Fix] Android: "dataLen longer than allowed" (regression in 1.14.13)
1.14.13
- [Fix] iOS: onMtu was not called (bug in original
flutter_blue) - [Feature] iOS & Android:
writeCharacteristic: addallowLongWriteoption to do longer writes
1.14.12
- [Fix] Android:
autoconnectwas not working. (regression sometime after 1.4.0) - [Cleanup] Android: cleanup
bmAdvertisementData - [Improve] iOS: check that characteristic supports READ, WRITE, WRITE_NO_RESP properties and throw error otherwise
1.14.11
- [Deprecate] dart:
isDiscoveringServices&servicesStream. They can be easily implemented yourself
1.14.10
- [Fix] iOS: scan results with empty manufacturer data was not parsed (bug in original
flutter_blue)
1.14.9
- [Fix] iOS:
disconnectReasonCode&disconnectReasonStringare mixed up (bug from when feature was added)
1.14.8
- [Feature] Dart: add
device.disconnectReason - [Improve] Dart: breaking change: rename
bondState()->bondState - [Fix] Dart: calling
connectordisconnectmultiple times should not re-push to connectionState stream (regression in 1.14.0) - [Fix] Android: calling
connectordisconnectmultiple times could fail(regression in 1.14.7) - [Fix] Android: security exception on
startScanfor some phones (regression in 1.13.4) - [Fix] Dart: various streams could push values out of order (bug in original
flutter_blue)
1.14.7
[Fix] Android: connected & disconnected states not received (regression in 1.14.4)
1.14.6
[Fix] iOS: disconnect would timeout if already disconnected (regression in 1.14.0)
1.14.5
- [Improve] Dart:
adapterState,bondState,mtu,connectiontatecould miss changes due to race conditions
1.14.4
- [Improve] Dart: deprecate
disconnecting&connectingstates, they're not actually streamed by Android or iOS - [Improve] Dart: increase default connection timeout 15 -> 35 seconds to slightly exceed android & iOS defaults
- [Improve] Example: unsubscribe snackbar showed 'Subscribe: Success' incorrectly
- [Improve] Example: add snackbar color blue & red for success & fail
- [Improve] Example: add spinner while connecting or disconnecting
- [Improve] Example: do not continually call
connectedSystemDevice& RSSI
1.14.3
- [Improve] Example: was using deprecated variable name
1.14.2
- [Improve] Dart:
knownServicesshould be fully cleared on disconnection - [Improve] Dart: error handling: return more descriptive timeout exceptions
1.14.1
- [Improve] Dart: each
FlutterBluePlusExceptionshould have unique code for handling
1.14.0
This release improves bonding support.
- [feature] Android: expose
BluetoothDevice.bondState - [remove] changes regarding bond state made in 1.13.0 in favor of exposing bondState
- [refactor] BluetoothDevice & Android bond handling to improve reliablility & error handling.
- [Fix] Dart: BluetoothDevice:
connect&disconnectand others could incorrectly timeout (bug in originalflutter_blue) - [Fix] Dart: BluetoothDevice:
getBondState,getMtu,getConnectionStatecould skip values (bug in originalflutter_blue) - [Fix] Dart: clear
servicesListafter disconnection. Android requires you calldiscoverServicesagain - [Improve] Example: Subscribe button was not updating
- [Improve] Android: prefer
result.errorover exceptions - [Improve] Example: show snackbars on success as well
1.13.4
- [Fix] Android:
discoverServicesnever returns (regression in 1.13.0) - [Fix] Android:
turnOn&turnOffmust check for permissions (bug in originalflutter_blue) - [Fix] Android:
startScanshould not requiredBLUETOOTH_CONNECTpermission (bug in originalflutter_blue)
1.13.3
- [Fix] Dart: be extra careful to only call connect & disconnect when necessary (regression in 1.13.0)
1.13.2
- [Fix] Dart: connect should be no-op if already connected (regression in 1.13.1)
- [Improve] Dart: BluetoothDevice: use mutexes to prevent multiple in flight requests
1.13.1
- [Fix] Android/iOS: on connection failure, return right away (bug in original
flutter_blue) - [Improve] Android/iOS: on connection failure, return error code and error string
1.13.0
This release improves bonding support.
- [Fix] Android:
discoverServices& others can fail if currently in the process of bonding (bug in originalflutter_blue) - [Improve] Android:
createBond: check for success and throw exception on failure - [Improve] Android:
removeBond: returnFuture(void)instead ofFuture(Bool), and throw exception on failure
1.12.14
- [Fix] Android: min sdk is currently 21, not 19 (bug in original
flutter_blue) - [Fix] Android:
getOrDefaultnot available in AndroidSdkLevel < 24 (regression in 1.7.0) - [Improve] Android: log: BOND changes
- [rename] Android:
pair->createBond
1.12.13
- [Fix] iOS:
FlutterBluePlus.isAvailable'int' is not a subtype of type 'FutureOr' (regressed in 1.12.10)
1.12.12
- [Fix] Android: null ptr deref during
ScanResultconnectionState(regressed in 1.10.6) ^^^ connectionState was added to scanResults last week. It was not a good idea, and is now fully removed.
1.12.11
- [Fix] Android: potential null dereference if the platform does not have bluetooth (bug in original
flutter_blue) - [Fix] Android:
DeadObjectException: close all connections when bluetooth is turned off (bug in originalflutter_blue)
1.12.10
- [Fix] iOS:
isAvailablereturns false the first time, incorrectly (bug in originalflutter_blue) - [Fix] iOS: descriptors, must handle
NSData,NSString, &NSNumbercorrectly (bug in originalflutter_blue) - [Improve] Android:
turnOffis deprecated in Android
1.12.9
- [Fix] Dart:
servicesStream: 'bad state: Stream has already been listened to' (bug in originalflutter_blue) - [Fix] Dart: remove unecessary print (regression in 1.11.7)
- [Fix] Android: add blank
AndroidManifest.xmlto fix build errors in older flutter (regression in 1.12.0) - [Fix] Android/iOS: infinite recursion when included services includes itself (bug in original
flutter_blue) - [Fix] iOS:
FlutterBluePlus.isOnreturns 'no' first time even though it is on (bug in originalflutter_blue) - [Improve] Dart: mutex should make sure writes happen in the same order as called
- [Improve] Dart:
setLogLevelcolor now optional
1.12.8
- [Fix] Android: null ptr in
setPreferredPhy&setConnectionPriority(regression in 1.7.0)
1.12.7
- [Fix] iOS: mtu returned on iOS was 3 too small (bug in original
flutter_blue) - [Improve] Dart: simplify mutexes. improves throughput for chrs that support
write&writeWithoutResponse
1.12.6
- [Improve] Dart: verbose logging: brown == data from platform
1.12.5
- [Improve] Dart: add more logging when in verbose mode, with color
1.12.4
- [Fix] Android: build error typo (regression in 1.12.3)
1.12.3
- [Fix] Android:
mConnectionState&mMtunot cleared whenonDetachedFromEngine(regression in 1.10.10)
1.12.2
- [Fix] Example: Android: add back
INTERNETpermission for debug and profile modes. needed for debugging (regression in 1.12.0) - [Improve] Android: create
BluetoothManagerduringonMethodCall, as opposed to app startup
1.12.1
- [Improve] Android: simplify
build.gradeto not set specific gradle version. it is uneeded
1.12.0
This release simplifies permissions.
- [Improve] Android: remove permissions from plugin. It is easier for user to specify everything
- [Fix] Dart:
scancould be initiated twice causing bad state (bug in originalflutter_blue) - [Fix] Dart: read & write mutexs must always come from the
MutexFactoryto properly prevent race conditions
1.11.8
- [Fix] Android/iOS:
setLogLevel,getAdapterState,getAdapterNamereturning error when adapter not available
1.11.7
- [Fix] Dart: ensure only 1 mutex per characteristic to prevent race issues and dropped packets (bug in original
flutter_blue) - [perf] Dart:
writeWithoutResponseshould use at least 1 mutex perremoteId, to improve throughput - [Improve] Example: word wrapping on smaller screens
1.11.6
- [Fix] Dart:
writeWithoutResponseshould have its own mutex to prevent dropped packets (bug in originalflutter_blue)
1.11.5
- [Fix] iOS: crash
discoverServicescrash after bluetooth adapter is toggled on/off (regressed sometime after 1.4.0) - [Improve] Example: dismiss
DeviceScreenwhen bluetooth adapter is turned off - [Improve] Android/iOS: log
adapterStateandconnectionStateas strings
1.11.4
- [Fix] Android: null ptr exception getting Mtu (regression in 1.10.10)
1.11.3
- [Fix] Dart:
writeWithoutResponseshould wait for completion, to prevent dropped packets (bug in originalflutter_blue)
1.11.2
- [Improve] Android: remove
shouldClearGattCacheconnect option. It should be discouraged (called manually) (added in ~1.6.0)
1.11.1
- [Improve] Dart: add back
servicesList, but with simpler api
1.11.0
This release removes recent changes to the API causing issues.
- [remove] Dart:
includeConnectedSystemDevicesscan setting, it was too complicated - [remove] Dart:
servicesList(introduced in 1.10.6) - [rename] Dart:
connectedDevices->connectedSystemDevices
1.10.10
- [Fix] Android: platform exception when scanning with
includeConnectedSystemDevices(regression in 1.10.6) - [Fix] Dart: characteristic write crashed for negative values (regression in 1.7.0)
- [Fix] Dart:
connectionStateshould only be concerned with our appsconnectionState(bug in originalflutter_blue)
1.10.9
- [Fix] Android:
turnOnandturnOffcould timeout if already on or already off (regression in 1.10.0)
1.10.8
- [Fix] Android:
requestMtu(regression in 1.10.6)
1.10.7
- [Improve] Dart:
disconnectshould wait for disconnect to complete
1.10.6
- [Improve] Dart: for convenience, scan results now also include connected devices see:
includeConnectedDevice - [Improve] Dart: add
connectionStatetoScanResult - [Improve] Dart: add
BluetoothDevice.servicesListfor convenience, which callsdiscoverServicesautomatically. - [rename] Dart:
BluetoothDevice.services->BluetoothDevice.servicesStream
1.10.5
- [Fix] iOS: "API MISUSE: Cancelling connection for unused peripheral."
- [Improve] iOS: remove unecessary search of already connected devices during connection
1.10.4
- [Improve] iOS: add
remoteIdto error strings when connection fails, etc
1.10.3
- [Improve] Android: handle scan failure.
- [Improve] Dart: add verbose log level and remove unused log levels
1.10.2
- [Fix] Dart:
setLogLevelrecursion (regression in 1.10.0) - [Improve] iOS: use
NSErrorinstread of obj-c exceptions to avoid uncaught exceptions
1.10.1
- [Improve] Example: add error handling to descriptor read & write
1.10.0
This release improves error handling and reliability.
- [BREAKING CHANGE] Dart:
turnOn&turnOffnow wait for completion, return void instead of bool, and can throw - [BREAKING CHANGE] Dart: use static functions for
FlutterBluePlusinstead ofFlutterBluePlus.instance. Multiple instances is not supported by any platform. - [Improve] readme: add error handling section
- [Improve] iOS: handle missing bluetooth adapter gracefully
- [Improve] iOS:
getAdapterState&&getConnectionStateare more robust - [Improve] Android: log method call in debug, and more consistent log messages
- [Improve] Example: show nicer looking errors
- [Improve] Example: prefer
try/catchovercatchErroras dart debugger doesn't work withcatchErroras well
1.9.5
- [Fix] iOS:
serviceUUIDsalways null in scan results (regression in 1.7.0) - [Fix] Example: snackbar complaining about invalid contexts
1.9.4
- [Fix] iOS: characteristic read not working. (regression in 1.9.0)
- [Improve] Dart: handle
device.readRssifailure inrssiStreamgracefully
1.9.3
- [Fix] iOS:
setNotifyreturning error even though it succeeded (regression in 1.9.0) - [Fix] Dart:
Characteristic.isNotifyingwas not working (regression in 1.9.0) - [Improve] Dart: add back uuid convenience variable for
BluetoothDescriptor(deprecated in 1.8.6) - [Improve] Example: only show READ/WRITE/SUBSCRIBE buttons if the characteristic supports it
- [Improve] Example: add error handling
1.9.2
- [Fix] Dart:
readRssi: "Invalid argument: Instance of 'DeviceIdentifier'" (regression in 1.9.0)
1.9.1
- [Fix] Dart: crash in scanning due to assuming uuid is Guid format when it might not (regression in 1.9.0)
- [Improve] Dart:
BluetoothCharacteristic.onValueReceivedshould only stream successful reads (bug in 1.9.0) - [Improve] Dart: add convenience accessors for
BluetoothService.uuidandBluetoothCharacteristic.uuidas (deprecated in 1.8.6) - [Improve] Example: add macos support
1.9.0
This release marks the end of major work to improve reliability and simplicity of the FlutterBluePlus codebase. Please submit bug reports.
- [Breaking Change/Fix] Android: When
readis calledonValueChangedStreamis pushed to as well. This change was made to make both platforms behave the same way. It is an unavoidable limitation of iOS. See: https://github.com/boskokg/flutter_blue_plus/issues/419 - [Fix] Android/iOS: mtu check minus 3 issue (reggression in 1.8.3)
- [Fix] Dart:
BluetoothCharacteristic.statevariable not working (reggression in 1.8.6) - [Fix] Dart:
FlutterBluePlus.statevariable not working (reggression in 1.8.6) - [rename]
BluetoothCharacteristic.value->lastValueStream - [rename]
BluetoothDescriptor.value->lastValueStream - [rename]
BluetoothCharacteristic.onValueChangedStream->onValueReceived - [rename]
BluetoothDescriptor.onValueChangedStream->onValueReceived - [refactor] Dart:
adapterStateto usemethodChannel - [refactor] Dart: various 'bm' message schemas to use simpler characteristic structure
- [refactor] Dart:
BmSetNotificationResponseremoved. It is simpler to reuseBmWriteDescriptorResponse - [refactor] Android: move
secondaryServiceUuidcode its owngetServicePairfunction - [refactor] Android: android
MessageMakerto be a bit more legible
1.8.8
- [Fix] Android/iOS:
connectionStatenot being updated (regression in 1.8.6) - [Fix] Android:
adapterStateshouldve beengetAdapterState(regression in 1.8.6)
1.8.7
- [Improve] Dart: add 15 seconds default timeout for ble communication
1.8.6
- [rename] Dart:
BluetoothDevice.id->remoteId - [rename] Dart: uuid ->
characteristicUuid/serviceUuid/descriptorUuid - [rename] Dart:
FlutterBluePlus.name->adapterName - [rename] Dart:
BluetoothDevice.name->localName - [rename] Dart:
FlutterBluePlus.state->adapterState - [rename] Dart:
BluetoothDevice.state->connectionState - [Improve] iOS: add support for
autoReconnect(iOS 17 only)
1.8.5
- [Fix] iOS: check for nil peripheral. (regression in 1.8.3)
- [Fix] Android: clean up gatt servers
onDetachedFromEngine(bug in originalflutter_blue)
1.8.4
- [Improve] Android: make connectivity checks more robust
1.8.3
- [Improve] Android:
writeCharacteristic: return error if longer than mtu - [Improve] Android: add device connection checks
- [Improve] iOS: add mtu size checks
- [Improve] iOS: add device connection checks
- [refactor] iOS: unify try catch blocks
1.8.2
- [Improve] Android: support sdk 33 for
writeCharacteristicandwriteDescriptor - [Improve] Android: calling
connecton already connected device is now considered success - [Improve] Android: return more specific error for
locateGattissue - [Improve] Android:
shouldClearGattCacheis now called after connection, not before
1.8.1
- [Fix] Android: characteristic properties check was incorrect (regression in 1.7.8)
1.8.0
This release improves error handling.
- [Improve] android/ios: handle errors for
charactersticRead - [Improve] android/ios: handle errors for
readDescriptor - [Improve] android/ios: handle errors for
discoverServices - [Improve] android/ios: handle errors for
mtu - [Improve] android/ios: handle errors for
readRssi - [Improve] android/ios: pass error string for
setNotifyValue - [Improve] android/ios: pass error string for
charactersticWrite - [Improve] android/ios: pass error string for
writeDescriptor
1.7.8
- [Improve] Android: add more useful errors for read and write characterist errors
1.7.7
- [Fix] Dart: scanning: "Bad state: Cannot add event after closing" (regression in 1.5.0)
- [Improve] Android: set
autoConnectto false by default - [Improve] Example: remove
pubspec.lockso users default to latest version
1.7.6
- [Fix] Dart:
BmBluetoothService.is_primarywas not set (regression in 1.7.0) - [Fix] Android:
BmAdvertisementData.connectablewas not set (regression in 1.7.0) - [Fix] Android: success was not set for
writeCharacteristic,setNotification,writeDescriptor(regression in 1.7.0) - [Improve] Android: update to gradle 8
- [Improve] Android: dont request
ACCESS_FINE_LOCATIONby default (Android 12+)
1.7.5
- [Fix] Android:
BluetoothAdapterStatenot being updated (regression in 1.7.0) - [Improve] Example: fix deprecations
- [Improve] Dart: remove
analysis_options.yaml
1.7.4
- [Fix] Android: Android 13 access fine location error (bug in original
flutter_blue)
1.7.3
- [Fix] Android: exception thrown when
descriptor.writeis called (regression in 1.7.0)
1.7.2
- [Fix] Android: exception thrown when
characteristic.writeis called (regression in 1.7.0) - [Fix] Android:
bmCharacteristicPropertieswas not being set correctly (regression in 1.7.0)
1.7.1
- [Fix] iOS: when connecting, exception is thrown (regression in 1.7.0)
1.7.0
This release removes Protobuf.
- [refactor] removed protobuf dependency
- [Fix] Android:
turnOnandturnOffnot working (regression in 1.6.1) - [Fix] Dart:
guidexception withserviceUUIDis empty (bug in originalflutter_blue) - [Improve] Android:
compileSdkVersion31 -> 33 - [Improve] Android: increase
minSdkVersion19 -> 21 to remove lollipop checks - [Improve] Android: FineLocation permission is now optional. See
startScan - [Improve] iOS: allow connecting without scanning if you save and reuse the
remote_id
1.6.1
- [Fix] Android: compile error (regression in 1.6.0)
- [Improve] Android: significantly clean up all code
1.6.0
This release reformats a bunch of Android code.
- [Fix] Dart: close
BufferStreamlisten on stopScan (regression in 1.5.0) - [Improve] Dart: don't repropogate Mutex error
- [Improve] Dart: better stacktrace on error for Characteristic Read/Write
- [Improve] MacOS: use symbolic links to iOS version, to keep internal code in sync
- [Improve] Android: reformat code
1.5.2
- [Fix] Android: setNotification was throwing exception (regression in 1.5.0)
1.5.1
- [Fix] Dart: issue where startScan can hang forever (regression in 1.5.0)
- [Fix] Dart: some scanResults could be missed due to race condition (bug in original
flutter_blue) - [Improve] Dart: dont export util classes & functions. they've been made library-private.
- [Improve] iOS: prepend all iOS logs with '[FBP-iOS]' prefix
- [Improve] iOS: log errors on failure
- [Improve] iOS: logs now adhere to logLevel
1.5.0
This release closes many open issues on Github.
- [Fix] Dart:
writeCharacteristic(and other similar functions) exception could be missed (bug in originalflutter_blue) - [Fix] Dart:
setNotifyValueshould check for success and throw error on failure (bug in originalflutter_blue) - [Fix] Dart: race conditions in
connect,disconnect,readRssi,writeCharacteristic,readCharacteristic(bug in originalflutter_blue) - [Fix] iOS: Bluetooth adapter being stuck in unknown state (bug in original
flutter_blue) - [Fix] iOS: dropping packets during bulk write without response (bug in original
flutter_blue) - [Improve] Example: android permissions
- [Improve] Dart: add isScanningNow variable
- [Improve] add support for macOS
- [Improve] Android: replace deprecated bluetooth enable with
Enable-Intent - [Improve] Android: Removed
maxSdkVersion=30in manifest - [Improve] Android: add function:
setPreferredPh - [Improve] Android: add function:
removeBond - [Improve] Android: add function:
requestConnectionPriority - [Improve] Android: allow for simultaneous MAC and ServiceUuid ScanFilters
- [Improve] Android: request location permission on Android 12+ when scanning (needed on some phones)
- [Improve] iOS: Use
CBCentralManagerOptionShowPowerAlertKeyfor better UI popups - [Improve] Dart: Removed RxDart and other dependencies
Chip Weinberger Becomes Maintainer
1.4.0
-
Android: Add clear gatt cache method #142 (thanks to joistaus)
-
Android: Opt-out of the
neverForLocationpermission flag for theBLUETOOTH_SCANpermission. (thanks to navaronbracke)If
neverForLocationis desired, opt back into the old behavior by adding an explicit entry to your Android Manifest:<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> -
Android: Scan BLE long range -devices #139 (thanks to jonik-dev)
-
Android: Prevent deprecation warnings #107 (thanks to sqcsabbey)
-
Allow native implementation to handle pairing request #109 (thanks to JRazek)
1.3.1
- Reverted: Ios: fixed manufacturer data parsing #104 (thanks to sqcsabbey)
1.3.0
- Ios: fixed manufacturer data parsing #104 (thanks to sqcsabbey)
- Ios: Fixed an error when calling the connect method of a connected device #106 (thanks to figureai)
- Android: Scan Filter by Mac Address #57 (thanks to Zyr00)
- Upgrading to linter 2.0.1, excluding generated ProtoBuf files from linting. (thanks to MrCsabaToth)
1.2.0
- connect timeout fixed (thanks to crazy-rodney, sophisticode, SkuggaEdward, MousyBusiness and cthurston)
- Add timestamp field to ScanResult class #59 (thanks to simon-iversen)
- Add FlutterBlue.name to get the human readable device name #93 (thanks to mvo5)
- Fix bug where if there were multiple subscribers to FlutterBlue.state and one cancelled it would accidentally cancel all subscribers (thank to MacMalainey and MrCsabaToth)
1.1.3
- Read RSSI from a connected BLE device #1 (thanks to sophisticode)
- Fixed a crash on Android OS 12 (added check for BLUETOOTH_CONNECT permission) (fixed by dspells)
- Added BluetoothDevice constructor from id (MAC address) (thanks to tanguypouriel)
- The previous version wasn't disconnecting properly and the device could be still connected under the hood as the cancel() was not called. (fixed by killalad)
- dependencies update (min micro version updating)
1.1.2
- Remove connect to BLE device after BLE device has disconnected #11 (fixed by sophisticode)
- fixed Dart Analysis warnings
1.1.1
- Copyright reverted to Paul DeMarco
1.1.0
- Possible crash fix caused by wrong raw data (fixed by narrit)
- Ios : try reconnect on unexpected disconnection (fixed by EB-Plum)
- Android: Add missing break in switch, which causes exceptions (fixed by russelltg)
- Android: Enforcing maxSdkVersion on the ACCESS_FINE_LOCATION permission will create issues for Android 12 devices that use location for purposes other than Bluetooth (such as using packages that actually need location). (fixed by rickcasson)
1.0.0
- First public release
FORKED FLUTTER_BLUE
0.12.0
- Supporting Android 12 Bluetooth permissions. #940
0.12.0
- Delay Bluetooth permission & turn-on-Bluetooth system popups on iOS #964
0.11.0
- The timeout was throwing out of the Future's scope #941
- Expose onValueChangedStream #882
- Android: removed V1Embedding
- Android: removed graddle.properties
- Android: enable background usage
- Android: cannot handle devices that do not set CCCD_ID (2902) includes BLUNO #185 #797
- Android: add method for getting bonded devices #586
- Ios: remove support only for x86_64 simulators
- Ios: Don't initialize CBCentralManager until needed #599
0.10.0
- mtuRequest returns the negotiated MTU
- Android: functions to turn on/off bluetooth
- Android: add null check if channel is already teared down
- Android: code small refactoring (fixed AS warnings)
- Android: add null check if channel is already teared down
- Ios: widen protobuf version allowed
0.9.0
- Android migrate to mavenCentral.
- Android support build on Macs M1
- Android protobuf-gradle-plugin:0.8.15 -> 0.8.17
- Ios example upgrade to latest flutter 2.5
- deprecated/removed widgets fixed in example
0.8.0
- Migrate the plugin to null safety.
0.7.3
- Fix Android project template files to be compatible with protobuf-lite.
- Add experimental support for MacOS.
0.7.2
- Add
allowDuplicatesoption tostartScan. - Fix performance issue with GUID initializers.
0.7.1+1
- Fix for FlutterBlue constructor when running on emulator.
- Return error when attempting to
discoverServiceswhile not connected.
0.7.1
- Fix incorrect value notification when write is performed.
- Add
toStringto each bluetooth class. - Various other bug fixes.
0.7.0
- Support v2 android embedding.
- Various bug and documentation fixes.
0.6.3+1
- Fix compilation issue with iOS.
- Bump protobuf version to 1.0.0.
0.6.3
- Update project files for Android and iOS.
- Remove dependency on protoc for iOS.
0.6.2
- Add
mtuandrequestMtuto BluetoothDevice.
0.6.0+4
- Fix duplicate characteristic notifications when connection lost.
- Fix duplicate characteristic notifications when reconnecting.
- Add minimum SDK version of 18 for the plugin.
- Documentation updates.
0.6.0
- Breaking change. API refactoring with RxDart (see example).
- Log a more detailed warning at build time about the previous AndroidX migration.
- Ensure that all channel calls to the Dart side from the Java side are done on the UI thread. This change allows Transactions to work with upcoming Engine restrictions, which require channel calls be made on the UI thread. Note this is an Android only change, the iOS implementation was not impacted.
0.5.0
- Breaking change. Migrate from the deprecated original Android Support Library to AndroidX. This shouldn't result in any functional changes, but it requires any Android apps using this plugin to also migrate if they're using the original support library.
0.4.2+1
- Upgrade Android Gradle plugin to 3.3.0.
- Refresh iOS build files.
0.4.2
- Set the verbosity of log messages with
setLogLevel. - Updated iOS and Android project files.
autoConnectnow configurable for Android.- Various bug fixes.
0.4.1
- Fixed bug where setNotifyValue wasn't properly awaitable.
- Various UI bug fixes to example app.
- Removed unnecessary intl dependencies in example app.
0.4.0
- Breaking change. Manufacturer Data is now a
Mapof manufacturer ID's. - Service UUID's, service data, tx power level packets fixed in advertising data.
- Example app updated to show advertising data.
- Various other bug fixes.
0.3.4
- Updated to use the latest protobuf (^0.9.0+1).
- Updated other dependencies.
0.3.3
scanwithServicesto filter by service UUID's (iOS).- Error handled when trying to scan with adapter off (Android).
0.3.2
- Runtime permissions for Android.
scanwithServicesto filter by service UUID's (Android).- Scan mode can be specified (Android).
- Now targets the latest android SDK.
- Dart 2 compatibility.
0.3.1
- Now allows simultaneous notifications of characteristics.
- Fixed bug on iOS that was returning
discoverServicestoo early.
0.3.0
- iOS support added.
- Bug fixed in example causing discoverServices to be called multiple times.
- Various other bug fixes.
0.2.4
- Breaking change. Upgraded to Gradle 4.1 and Android Studio Gradle plugin 3.0.1. Older Flutter projects need to upgrade their Gradle setup as well in order to use this version of the plugin. Instructions can be found here.
0.2.3
- Bug fixes
0.2.2
- Breaking changes:
startScanrenamed toscan.ScanResultnow returns aBluetoothDevice.connectnow takes aBluetoothDeviceand returns Stream. - Added parameter
timeouttoconnect. - Automatic disconnect on deviceConnection.cancel().
0.2.1
- Breaking change. Removed
stopScanfrom API, usescanSubscription.cancel()instead. - Automatically stops scan when
startScansubscription is canceled (thanks to @brianegan). - Added
timeoutparameter tostartScan. - Updated example app to show new scan functionality.
0.2.0
- Added state and onStateChanged for BluetoothDevice.
- Updated example to show new functionality.
0.1.1
- Fixed image for pub.dartlang.org.
0.1.0
- Characteristic notifications/indications.
- Merged in Guid library, removed from pubspec.yaml.
0.0.1 - September 1st, 2017
- Initial Release.
