Giter Site home page Giter Site logo

boskokg / flutter_blue_plus Goto Github PK

View Code? Open in Web Editor NEW
693.0 14.0 435.0 2.33 MB

Flutter plugin for connecting and communicationg with Bluetooth Low Energy devices, on Android and iOS

License: Other

Java 33.99% Ruby 1.14% Swift 0.38% Objective-C 22.51% Dart 41.98%

flutter_blue_plus's Introduction

pub package Chat


FlutterBlue



Note: this plugin is continuous work from FlutterBlue.

Migrating from FlutterBlue? See Migration Guide

Contents

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.

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.

FlutterBluePlus was written to be simple, robust, and easy to understand.

No Dependencies

FlutterBluePlus has zero dependencies besides Flutter, Android, iOS, and macOS themselves.

This makes FlutterBluePlus very stable, and easy to maintain.

⭐ Stars ⭐

Please star this repo & on pub.dev. We all benefit from having a larger community.

Discord 💬

Chat There is a community Discord server. (Link)

Example

FlutterBluePlus has a beautiful example app, useful to debug issues.

cd ./example
flutter run

FlutterBlue

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. See Reference for a list of throwable functions.

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)

Setting LogLevel.verbose shows all data in and out.

⚫ = function name

🟣 = args to platform

🟡 = data from platform

Screenshot 2023-07-27 at 4 53 08 AM

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 (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` only returns live scan results, i.e. during scanning. Use
//  `scanResults` if you want live scan results *or* the results from a 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 (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 = device.mtuNow - 3; // 3 bytes ble overhead
    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: you must connect your app to them before you can communicate with them.

List<BluetoothDevice> devs = await FlutterBluePlus.systemDevices;
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

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>

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

Screenshot 2023-12-11 at 10 32 04 AM

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

Documentation: https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html

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.

You may also have to use https://pub.dev/packages/workmanager

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

Reference

🌀 = Stream ⚡ = synchronous

FlutterBluePlus API

Android iOS Throws Description
setLogLevel Configure plugin log level
setOptions Set configurable bluetooth options
isSupported Checks whether the device supports Bluetooth
turnOn 🔥 Turns on 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 Throws Description
events.onConnectionStateChanged 🌀 Stream of connection changes of all devices
events.onMtuChanged 🌀 Stream of mtu changes of all devices
events.onReadRssi 🌀 Stream of rssi reads of all devices
events.onServicesReset 🌀 Stream of services resets of all devices
events.onDiscoveredServices 🌀 Stream of services discovered of all devices
events.onCharacteristicReceived 🌀 Stream of characteristic value reads of all devices
events.onCharacteristicWritten 🌀 Stream of characteristic value writes of all devices
events.onDescriptorRead 🌀 Stream of descriptor value reads of all devices
events.onDescriptorWritten 🌀 Stream of descriptor value writes of all devices
events.onBondStateChanged 🌀 Stream of android bond state changes of all devices
events.onNameChanged 🌀 Stream of iOS name changes of all devices

BluetoothDevice API

Android iOS Throws 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?
isDisonnected ⚡ 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 Throws 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 Throws 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:

Scanning:

Connecting:

Reading & Writing:

Subscriptions:

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. Use this code:

// wait for actual adapter state, up to 3 seconds
Set<BluetoothAdapterState> inProgress = {BluetoothAdapterState.unknown, BluetoothAdapterState.turningOn};
var adapterState = FlutterBluePlus.adapterState.where((v) => !inProgress.contains(v)).first;
await adapterState.timeout(const Duration(seconds: 3)).onError((error, stackTrace) {
   throw Exception("Could not determine Bluetooth state. ${FlutterBluePlus.adapterStateNow}");
});

// check adapter state
if (FlutterBluePlus.adapterStateNow != BluetoothAdapterState.on) {
   throw Exception("Bluetooth Is Not On. ${FlutterBluePlus.adapterStateNow}");
}

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

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 withServices to 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.


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:

  1. you need to enable location permissions, see Getting Started
  2. you must pass androidUsesFineLocation:true to the startScan method.

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 is called for await chr.read() & await chr.write() & await chr.setNotifyValue(true)

onValueReceived is only called for await chr.read() & await chr.setNotifyValue(true)

2. your device has nothing to send

If you are using await 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.

flutter_blue_plus's People

Contributors

a1573595 avatar benderaze avatar boskokg avatar breadkey avatar chipweinberger avatar danielle-h avatar fewensa avatar figure-ai avatar fritzmatthaeus avatar jasaw avatar jrazek avatar keep-cloud-tr avatar krupikivan avatar manuel75o avatar mbalamut avatar mrcsabatoth avatar mvo5 avatar nairboon avatar navaronbracke avatar officelioneight avatar romcik077 avatar shatanikmahanty avatar shubhamsinghmutualmobile avatar sophisticode avatar sqcsabbey avatar temoa avatar tonimoeckel avatar tuna-f1sh avatar wcoder avatar zyr00 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter_blue_plus's Issues

I need to send data in Hexadecimal format

Very gratefull for this awesome bluetooth package for flutter.
For my problem i need to write data to a specific charachteristic in hexadecimal format on to a GATT server (UART service).
Using the write function on characteristic i see that the only available input it the list of int.
Is there a way to write to the charachteristic in hex format.
For example how to write this hex data (497100000000100A5D) to characteristic?

Write data is stopped when push to another page

I got this exception error
PlatformException(write_characteristic_error, writeCharacteristic failed, null, null)
I used a while loop to send data as long as the device is connected, but the writing process is stopped if I navigate/push to another page, How to make the write method keep running even we change the screen?

How can i check connecting device state?

Please help me!

How can i check connecting or disconnecting device state value in dart code?

I am using StreamBuilder. But it is only returning connected, disconnected device state value.

how to send greatter than 512 bytes

I have a file that is larger than 512 bytes to send to an esp32. I'm sending "withoutResponse: false", the flutter_blue_plus library does the split according to the mtu size without problems, but when it reaches 512 bytes it returns an error to write in characteristic. To solve this I have a function that splits the file and writes each 512 bytes.
Esp32 can send me files larger than 512 without doing anything. Can I send larger files without splitting?

Throwing platform exception in release mode while starting scan using FlutterBluePlus.instance.scan(timeout:Duration(seconds:30))

This is the exception I am getting when it calls the FlutterBluePlus.instance.scan(timeout:Duration(seconds:30))

Device: Samsung Galaxy Tab E SM-G973W
Android OS: 7.1.1
Flutter_Blue_Plus: 1.1.3
Flutter: 2.10.5

PlatformException(startScan, Field androidScanMode_ for i.b.a.g0 not found. Known fields are [private int i.b.a.g0.h, private i.c.b.b0$i i.b.a.g0.i, private boolean i.b.a.g0.j, private static final i.b.a.g0 i.b.a.g0.k, private static volatile i.c.b.a1 i.b.a.g0.l], java.lang.RuntimeException: Field androidScanMode_ for i.b.a.g0 not found. Known fields are [private int i.b.a.g0.h, private i.c.b.b0$i i.b.a.g0.i, private boolean i.b.a.g0.j, private static final i.b.a.g0 i.b.a.g0.k, private static volatile i.c.b.a1 i.b.a.g0.l]

How to read more than 20 bytes data (MTU negotation is not available)

Hello,

I have a problem to read the proper amount of data sent by BLE peripheral. The peripheral cannot send bigger packages than 20 bytes (MTU is not negotiable). It cuts every message into 20 bytes packets. Unfortunately, I am not able to catch the first few packets, just the last one. While i subscribe to a characteristic and force it to send data, I can't find a way to catch the single packets. I met similar problem on pure Android app, but there I was able to save each packet from a characteristic and then reuse it. Here, it seems like they disappear and only the last one is used. Any ideas in this case?
I will be very grateful for any insights.

FlutterBluePlus.state behaves strange.

There were similar issues in the upstream repository already:

And it's still an issue. In my case a class that is provided with provider package at the root of the widget tree is trying to keep connection with any device that can act as a gateway to a mesh network between IoT devices. It's doing this in the background and listens to the state field to do it only when Bluetooth is turned on.

In the same time widgets that require gateway connection, so user can make any interaction with the network, are listening state to indicate that gateway is not available, because Bluetooth is turned off (other reasons may be that it's just not around or location services are disabled). Of course it's abstracted to a single class like BluetoothNotAvailableDialog, but this still leaves a single instance of that service class and multiple instances of the dialog class and they cannot listen to state field at the same time, because only one of them receives events and the rest do not.

There already exists a pull request which fixes the issue. It's pretty small change so should be easy to review and merge.

Can't instantiate FlutterBluePlus in an Isolate function

Calling 'FlutterBluePlus.instance' asserts with: Cannot set the method call handler before the binary messenger has been initialized. This happens when you call setMethodCallHandler() before the WidgetsFlutterBinding has been initialized. You can fix this by either calling WidgetsFlutterBinding.ensureInitialized() before this or by passing a custom BinaryMessenger instance to MethodChannel().

(I noticed an old issue on the old 'flutter_blue' project which has sat untouched for two years. Is there any chance this could be made to work here?)

flutter_blue_plus\FlutterBluePlusPlugin.java uses or overrides a deprecated API

When I run flutter build apk, I get the following warning:

Note: D:\Users\cvanbeek\installs\flutter\.pub-cache\hosted\pub.dartlang.org\flutter_blue_plus-1.1.3\android\src\main\java\com\boskokg\flutter_blue_plus\FlutterBluePlusPlugin.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

Version Info:

flutter_blue_plus: 1.1.3

Flutter:

Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c860cba910 (4 weeks ago) • 2022-03-25 00:23:12 -0500
Engine • revision 57d3bac3dd
Tools • Dart 2.16.2 • DevTools 2.9.2

Is it possible to periodically get updated RSSI value of already discovered beacon while Scan is going on ?

Hi

I have this scenario

  1. I have beacon, that is set to send signal every 1 second
  2. I have set 120 seconds scan timeout while scanning for the BLE devices.
  3. The plugin discovers the beacon flawlessly.

Is it possible to periodically get updated RSSI value of already discovered beacon while Scan is going on? I m asking because scan timeout is 120 seconds and beacon send signals every 1 second. So logically, it will be good if the RSSI value gets updated while Scan is going on.

Thanks
Sabin

get BluetoothState.unknown at APP starting on iOS (iphone).

Hi, All

I follow normal start-up code of flutter_blue as below.

MaterialApp(
     // others code .......
     home: StreamBuilder <BluetoothState> (
            stream: FlutterBluePlus.instance.state,
            initialData: BluetoothState.turningOn,  // change here for testing
            builder: (cont, snapshot)  {
              final state = snapshot.data;                            
              if (state == BluetoothState.on) {
                return FindDoorPage(state: state);
              } else {
                return BluetoothOffScreen(state: state);          
              }
            })
);

But on IPhone 6 plus, it always gets the two status in debug message as below, and Page goes to BluetoothOffScreen().

flutter:  BluetoothState.turningOn
....
flutter:  BluetoothState.unknown

if turn off the Bluetooth and turn on again, the APP will work fine as normal.
In Android phone, the last BluetoothState result will be ON. no need turn off then on.

Does someone have same issue? Could you give me an advice?
Thanks!

--
IOS: 12.5.5
Flutter: 2.10.4
Dart : 2.16.2
macOS 12.2.1
CocoaPods version 1.10.2
FlutterBluePlus: 1.1.2

Not able to disconnect

Hi,

i used the library and it works well.
When i add at the main file this line of code (to not turn the device) the disconnect function doesn't work.

void main() async { WidgetsFlutterBinding.ensureInitialized(); await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown], ); runApp(const MyApp()); }

I think, that the problem comes becouse the disconnect is a future that doesn't have the async, await state. How can i solve the problem?

heart rate measurement characteristics not read

I used heart rate data for mi band4, 5
"00002a37-0000-1000-8000-00805f9b34fb" this uuid can be read on iOS, but not on Android.

Android was this characteristics.properties.read = false
but iOS return true
and also bonded using the mi band official app.
what should i do to solve this problem?

this is my code :

for (blep.BluetoothCharacteristic c in _service!.characteristics) {
  String uuid = "0x${c.uuid.toString().toLowerCase().substring(4, 8)}";
  if (c.properties.read) {
    if (c.isNotifying) {
      await c.setNotifyValue(true);
    }
    c.read();
    if (uuid == "0x2a37") {
      debugPrint(
          ":::::::::: Heart Rate Measurement => ${c.lastValue[1]} ::::::::::");
    } else if (uuid == "0x2a39") {
      debugPrint(
          ":::::::::: Heart Rate Control Point => ${c.lastValue[1]} ::::::::::");
    }
  }
}

How to get real Mac Address in iOS devices.?

In scan results, android shows real BT Mac address, while iOS don't. Seems that iOS encrypts the MAC Address and converts it to random GUUID instead.

Is it possible to get real BT Mac Address in iOS?

Thanks

Question regarding txPower, AoA and AoD

Hi,

I am not sure whether its issue or not, but I do have got few questions

  1. txPower always seems to be null for my beacons when checked via Android
  2. Bluetooth 5 transmits AoA and AoD (Angle of Arrival and Angle of Departure). This will help to find direction of the beacon. Is it possible to fetch these with this plugin?

Thanks a lot

Execution failed for task ':flutter_blue_plus:compileReleaseJavaWithJavac'. on Ubuntu 20.04

I have a Ubuntu build server that I'm trying to use to generate app APK files. When I run flutter build apk on the Linux server, it fails and I get the error below related to flutter_blue_plus. The interesting thing is that I tested the build on a Windows PC, and it worked fine. Both machines are running Flutter 2.10.5 and dart 2.16.2.

Here is the error message:

$ flutter build apk
💪 Building with sound null safety 💪
Running Gradle task 'assembleRelease'...                        
An exception has occurred in the compiler (1.8.0_312). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError: annotationType(): unrecognized Attribute name MODULE (class com.sun.tools.javac.util.UnsharedNameTable$NameImpl)
	at com.sun.tools.javac.util.Assert.error(Assert.java:133)
	at com.sun.tools.javac.code.TypeAnnotations.annotationType(TypeAnnotations.java:231)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.separateAnnotationsKinds(TypeAnnotations.java:294)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitMethodDef(TypeAnnotations.java:1066)
	at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:778)
	at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.scan(TypeAnnotations.java:275)
	at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitClassDef(TypeAnnotations.java:1042)
	at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:693)
	at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.scan(TypeAnnotations.java:275)
	at com.sun.tools.javac.code.TypeAnnotations$1.run(TypeAnnotations.java:127)
	at com.sun.tools.javac.comp.Annotate.flush(Annotate.java:152)
	at com.sun.tools.javac.comp.Annotate.enterDone(Annotate.java:129)
	at com.sun.tools.javac.comp.Enter.complete(Enter.java:512)
	at com.sun.tools.javac.comp.Enter.main(Enter.java:471)
	at com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:982)
	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:857)
	at com.sun.tools.javac.main.Main.compile(Main.java:523)
	at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
	at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
	at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:74)
	at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:94)
	at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
	at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:55)
	at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:40)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:97)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:51)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
	at org.gradle.api.internal.tasks.compile.AnnotationProcessorDiscoveringCompiler.execute(AnnotationProcessorDiscoveringCompiler.java:51)
	at org.gradle.api.internal.tasks.compile.AnnotationProcessorDiscoveringCompiler.execute(AnnotationProcessorDiscoveringCompiler.java:37)
	at org.gradle.api.internal.tasks.compile.ModuleApplicationNameWritingCompiler.execute(ModuleApplicationNameWritingCompiler.java:46)
	at org.gradle.api.internal.tasks.compile.ModuleApplicationNameWritingCompiler.execute(ModuleApplicationNameWritingCompiler.java:36)
	at org.gradle.api.internal.tasks.compile.CleaningJavaCompiler.execute(CleaningJavaCompiler.java:53)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalCompilerFactory.lambda$createRebuildAllCompiler$0(IncrementalCompilerFactory.java:98)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalResultStoringCompiler.execute(IncrementalResultStoringCompiler.java:61)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalResultStoringCompiler.execute(IncrementalResultStoringCompiler.java:45)
	at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler$2.call(CompileJavaBuildOperationReportingCompiler.java:59)
	at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler$2.call(CompileJavaBuildOperationReportingCompiler.java:51)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler.execute(CompileJavaBuildOperationReportingCompiler.java:51)
	at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:343)
	at org.gradle.api.tasks.compile.JavaCompile.performIncrementalCompilation(JavaCompile.java:237)
	at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:209)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
	at org.gradle.api.internal.project.taskfactory.IncrementalInputsTaskAction.doExecute(IncrementalInputsTaskAction.java:32)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
	at org.gradle.api.internal.project.taskfactory.AbstractIncrementalTaskAction.execute(AbstractIncrementalTaskAction.java:25)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.run(ExecuteActionsTaskExecuter.java:555)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:540)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:523)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:108)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:271)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:260)
	at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$0(ExecuteStep.java:33)
	at java.util.Optional.map(Optional.java:215)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:33)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:67)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:36)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:49)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:34)
	at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:43)
	at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
	at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
	at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:44)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:54)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:38)
	at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:42)
	at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:159)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:72)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:43)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:44)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:33)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:92)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:85)
	at java.util.Optional.map(Optional.java:215)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:55)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:[39](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L39))
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:94)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:79)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
	at java.util.Optional.orElseGet(Optional.java:267)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:[40](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L40))
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
	at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:187)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:179)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:[41](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L41))
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:[48](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L48))
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:11[49](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L49))
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:[56](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L56))
	at java.lang.Thread.run(Thread.java:[74](http://git.tda.local/ee/obpm/obpm-flutter/-/jobs/880#L74)8)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':flutter_blue_plus:compileReleaseJavaWithJavac'.
> Compilation failed; see the compiler error output for details.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org/

How using this package?

Hi,
I would like use this package for my Application Android and iOS.
But how use this package, there isn't on pub.dev.
Thanks

Android 12 not detecting beacons and some of the BLE devices.

This plugin works, but not as intended in Android 12.

In Android 12, the scan results in devices, but it is not discovering the beacons and some BLE devices. However same code in lower android versions discovers them. What I am doing wrong? Or is it an issue with plugin?

I have following in AndroidManifest.xml.


    <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.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />

    <!-- Needed only if your app communicates with already-paired Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

And in my code

I have requested permissions like this before scanning.

final permissionBT = await Permission.bluetooth.request().isGranted;
    final permissionBTScan = await Permission.bluetoothScan.request().isGranted;
    final permissionBTConnect =
        await Permission.bluetoothConnect.request().isGranted;
    final permissionBTAd =
        await Permission.bluetoothAdvertise.request().isGranted;
    final permissionLoc = await Permission.location.request().isGranted;
    final permissionLocALways =
        await Permission.locationAlways.request().isGranted;
    final permissionLocInUse = await Permission.locationWhenInUse.request().isGranted;

I am not being able to build an app.

I am not sure what I did wrong. When I tried to build the app, I get following error

An exception has occurred in the compiler (1.8.0_242-release). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError: annotationType(): unrecognized Attribute name MODULE (class com.sun.tools.javac.util.UnsharedNameTable$NameImpl)
	at com.sun.tools.javac.util.Assert.error(Assert.java:133)
	at com.sun.tools.javac.code.TypeAnnotations.annotationType(TypeAnnotations.java:231)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.separateAnnotationsKinds(TypeAnnotations.java:294)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitMethodDef(TypeAnnotations.java:1066)
	at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:778)
	at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.scan(TypeAnnotations.java:275)
	at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitClassDef(TypeAnnotations.java:1042)
	at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:693)
	at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
	at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.scan(TypeAnnotations.java:275)
	at com.sun.tools.javac.code.TypeAnnotations$1.run(TypeAnnotations.java:127)
	at com.sun.tools.javac.comp.Annotate.flush(Annotate.java:152)
	at com.sun.tools.javac.comp.Annotate.enterDone(Annotate.java:129)
	at com.sun.tools.javac.comp.Enter.complete(Enter.java:512)
	at com.sun.tools.javac.comp.Enter.main(Enter.java:471)
	at com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:982)
	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:857)
	at com.sun.tools.javac.main.Main.compile(Main.java:523)
	at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
	at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
	at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:74)
	at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:94)
	at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
	at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:55)
	at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:40)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:97)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:51)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
	at org.gradle.api.internal.tasks.compile.AnnotationProcessorDiscoveringCompiler.execute(AnnotationProcessorDiscoveringCompiler.java:51)
	at org.gradle.api.internal.tasks.compile.AnnotationProcessorDiscoveringCompiler.execute(AnnotationProcessorDiscoveringCompiler.java:37)
	at org.gradle.api.internal.tasks.compile.ModuleApplicationNameWritingCompiler.execute(ModuleApplicationNameWritingCompiler.java:46)
	at org.gradle.api.internal.tasks.compile.ModuleApplicationNameWritingCompiler.execute(ModuleApplicationNameWritingCompiler.java:36)
	at org.gradle.api.internal.tasks.compile.CleaningJavaCompiler.execute(CleaningJavaCompiler.java:53)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalCompilerFactory.lambda$createRebuildAllCompiler$0(IncrementalCompilerFactory.java:98)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalResultStoringCompiler.execute(IncrementalResultStoringCompiler.java:61)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalResultStoringCompiler.execute(IncrementalResultStoringCompiler.java:45)
	at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler$2.call(CompileJavaBuildOperationReportingCompiler.java:59)
	at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler$2.call(CompileJavaBuildOperationReportingCompiler.java:51)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.api.internal.tasks.compile.CompileJavaBuildOperationReportingCompiler.execute(CompileJavaBuildOperationReportingCompiler.java:51)
	at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:343)
	at org.gradle.api.tasks.compile.JavaCompile.performIncrementalCompilation(JavaCompile.java:237)
	at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:209)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
	at org.gradle.api.internal.project.taskfactory.IncrementalInputsTaskAction.doExecute(IncrementalInputsTaskAction.java:32)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
	at org.gradle.api.internal.project.taskfactory.AbstractIncrementalTaskAction.execute(AbstractIncrementalTaskAction.java:25)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.run(ExecuteActionsTaskExecuter.java:555)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:540)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:523)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:108)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:271)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:260)
	at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$0(ExecuteStep.java:33)
	at java.util.Optional.map(Optional.java:215)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:33)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:67)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:36)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:49)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:34)
	at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:43)
	at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
	at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
	at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:44)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:54)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:38)
	at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:42)
	at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:159)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:72)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:43)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:44)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:33)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:92)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:85)
	at java.util.Optional.map(Optional.java:215)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:55)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:39)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:94)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:79)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
	at java.util.Optional.orElseGet(Optional.java:267)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:40)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
	at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:187)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:179)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
	at org.gradle.execution.plan.DefaultPlanExecutor.process(DefaultPlanExecutor.java:72)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.executeWithServices(DefaultTaskExecutionGraph.java:184)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.execute(DefaultTaskExecutionGraph.java:177)
	at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:39)
	at org.gradle.execution.DefaultBuildWorkExecutor.execute(DefaultBuildWorkExecutor.java:40)
	at org.gradle.execution.DefaultBuildWorkExecutor.access$000(DefaultBuildWorkExecutor.java:24)
	at org.gradle.execution.DefaultBuildWorkExecutor$1.proceed(DefaultBuildWorkExecutor.java:48)
	at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:49)
	at org.gradle.execution.DefaultBuildWorkExecutor.execute(DefaultBuildWorkExecutor.java:40)
	at org.gradle.execution.DefaultBuildWorkExecutor.execute(DefaultBuildWorkExecutor.java:33)
	at org.gradle.execution.IncludedBuildLifecycleBuildWorkExecutor.execute(IncludedBuildLifecycleBuildWorkExecutor.java:36)
	at org.gradle.execution.DeprecateUndefinedBuildWorkExecutor.execute(DeprecateUndefinedBuildWorkExecutor.java:42)
	at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.run(BuildOperationFiringBuildWorkerExecutor.java:57)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor.execute(BuildOperationFiringBuildWorkerExecutor.java:42)
	at org.gradle.initialization.DefaultGradleLauncher.runWork(DefaultGradleLauncher.java:265)
	at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:174)
	at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150)
	at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:126)
	at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:72)
	at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:67)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:178)
	at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:67)
	at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:56)
	at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:63)
	at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
	at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:67)
	at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:49)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:44)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:44)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.lambda$execute$0(InProcessBuildActionExecuter.java:54)
	at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:87)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:53)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:29)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.lambda$execute$0(BuildTreeScopeLifecycleBuildActionExecuter.java:33)
	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:49)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:32)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:27)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:104)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:64)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:37)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.lambda$execute$0(SessionScopeLifecycleBuildActionExecuter.java:54)
	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:67)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:50)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:59)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
	at org.gradle.util.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.lang.Thread.run(Thread.java:748)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':flutter_blue_plus:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org

BUILD FAILED in 15s
Exception: Gradle task assembleDebug failed with exit code 1
Exited (sigterm)

SDK 31 Android 12 Solution

Since SDK 31 is required now:

( this was my solution to get it working on Android 12 and older devices. I'm open for suggestions.)


1. Go to Android Studio delete all other SDK and select to Install SDK31
(also upgrade Kotlin to 1.6.10 and all other things that it needs to upgrade)

check if you have installed sdk 31 with flutter doctor command in the terminal


2. Create a proguard-rules.pro file in android/app/
save it with this code:

-keepclassmembernames class com.boskokg.flutter_blue_plus.* { *; }
-keep class com.boskokg.flutter_blue_plus.** { *; }

3. Modify these gradle files:

android/app/build.gradle
(don't forget to change bundle name to yours)

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "YOUR.BUNDLE.NAME" <-change this
        minSdkVersion 21
        targetSdkVersion 31
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug

            // added things from here:

            minifyEnabled true
            useProguard true

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

android/build.gradle

buildscript {
    ext.kotlin_version = '1.6.10'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

android/gradle/wrapper/gradle-wrapper.properties

#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

4. Install permission_handler plugin from pub.dev


5. add this to your main function before runApp() or wherever you want to call for permissions.

if (Platform.isAndroid) {
    await Permission.locationWhenInUse.request();
    await Permission.bluetooth.request();
    await Permission.bluetoothScan.request();
    await Permission.bluetoothConnect.request();
  }

6. Add permissions to your android/app/src/main/AndroidManifest.xml

<manifest
(...)
     <!-- required for API 18 - 30 -->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    <!-- required for API 23 - 30 -->
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <!-- API 31+ -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />

(...)


<application
      (...)
      <activity
        (...)
            android:exported="true"

Android 12 permissions and manifest

Hi best bluetooth flutter developers in the world.

I tried an app and it works very well in android 11 and 10, but, when i switch to android 12 it says:

D/permissions_handler( 8510): Bluetooth permission missing in manifest

These are my permissions, what i have to do for let flutter_blue_plus works on android 12?

`


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


<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.BLUETOOTH_SCAN" />

<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />`

Caching GATT on IOS...

Moved from FlutterBlue, still having the same problem...
2A00 -- Device Name isn't showing up in the GATT. It is in there in reality and is visible on Android.
I've tried turning Bluetooth on/off and rebooting the iPhone...

IOS Log:

2022-02-03 16:29:26.178508-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:26.176052 Connecting to 8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1...
2022-02-03 16:29:26.179884-0600 Runner[1020:128813] flutter: WannaConnect
2022-02-03 16:29:26.179987-0600 Runner[1020:128813] flutter: GonnaConnect
2022-02-03 16:29:26.838047-0600 Runner[1020:128483] didConnectPeripheral
2022-02-03 16:29:26.849271-0600 Runner[1020:128813] flutter: then
2022-02-03 16:29:26.850926-0600 Runner[1020:128813] flutter: return
2022-02-03 16:29:26.851550-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:26.851442 ConnectDone
2022-02-03 16:29:27.531254-0600 Runner[1020:128483] didDiscoverServices
2022-02-03 16:29:27.531635-0600 Runner[1020:128483] Found service: E4CF7947-AD98-425B-8F0C-571F873A88FC
2022-02-03 16:29:27.531930-0600 Runner[1020:128483] Found service: 180A
2022-02-03 16:29:27.532084-0600 Runner[1020:128483] Found service: 1815
2022-02-03 16:29:27.532205-0600 Runner[1020:128483] Found service: 3A9057FB-6F8A-4D7E-AD45-62B1E4B2F4F3
2022-02-03 16:29:27.532319-0600 Runner[1020:128483] Found service: 3A9057FB-6F8A-4F7E-AE45-62BCE4B2F4F1
2022-02-03 16:29:27.532441-0600 Runner[1020:128483] Found service: 1805
2022-02-03 16:29:27.532580-0600 Runner[1020:128483] Found service: 181A
2022-02-03 16:29:27.532701-0600 Runner[1020:128483] Found service: 1828
2022-02-03 16:29:27.532822-0600 Runner[1020:128483] Found service: 1D14D6EE-FD63-4FA1-BFA4-8F47B42119F0
2022-02-03 16:29:27.708441-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:27.889213-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:27.981268-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.039130-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.340595-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.398334-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.518781-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.608596-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.728428-0600 Runner[1020:128483] didDiscoverCharacteristicsForService
2022-02-03 16:29:28.787918-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.788080-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847465-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847588-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847634-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847672-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847704-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847738-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847771-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.847975-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.848096-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.848161-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.848227-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.848286-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.907979-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:28.967715-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.087787-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.148049-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.208359-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.267973-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.328643-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.417654-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.478226-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.538169-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.598341-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.658771-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.658975-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.659059-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.659138-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.659214-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.659289-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.718429-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.718652-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.718736-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.718815-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.718891-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.807972-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.868611-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.868845-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.868938-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.869016-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.869092-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:29.928516-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.017232-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.139659-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.228282-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.288047-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.288255-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.288324-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.288386-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348139-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348353-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348421-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348484-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348547-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348610-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.348669-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.408406-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.467502-0600 Runner[1020:128483] didDiscoverDescriptorsForCharacteristic
2022-02-03 16:29:30.467844-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.467978-0600 Runner[1020:128483] service uuid:e4cf7947-ad98-425b-8f0c-571f873a88fc
2022-02-03 16:29:30.468234-0600 Runner[1020:128483] uuid: 78805e56-f8b7-4f30-a056-2ece9f4f70a9 value: (null)
2022-02-03 16:29:30.468449-0600 Runner[1020:128483] uuid: 665c1cbc-2c88-4ae1-9ccf-9dbc8a9e5440 value: (null)
2022-02-03 16:29:30.468551-0600 Runner[1020:128483] uuid: 00002ac8-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.468667-0600 Runner[1020:128483] uuid: 665c1cbc-2c88-4ae1-9ccf-9dbc8a9e5460 value: (null)
2022-02-03 16:29:30.468749-0600 Runner[1020:128483] uuid: 665c1cbc-2c88-4ae1-9ccf-9dbc8a988440 value: (null)
2022-02-03 16:29:30.468825-0600 Runner[1020:128483] uuid: 1f8783f9-06db-4982-a0ae-e78f146ec53f value: (null)
2022-02-03 16:29:30.468904-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.468968-0600 Runner[1020:128483] service uuid:0000180a-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.469070-0600 Runner[1020:128483] uuid: 00002a29-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469162-0600 Runner[1020:128483] uuid: 00002a24-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469252-0600 Runner[1020:128483] uuid: 00002a25-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469330-0600 Runner[1020:128483] uuid: 1f8783f9-06db-4982-a0ae-e78f146ec53f value: (null)
2022-02-03 16:29:30.469435-0600 Runner[1020:128483] uuid: 00002a27-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469537-0600 Runner[1020:128483] uuid: 00002a28-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469627-0600 Runner[1020:128483] uuid: 00002a23-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469729-0600 Runner[1020:128483] uuid: 00002a85-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.469801-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.469865-0600 Runner[1020:128483] service uuid:00001815-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.469962-0600 Runner[1020:128483] uuid: 00001229-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470087-0600 Runner[1020:128483] uuid: 00001230-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470209-0600 Runner[1020:128483] uuid: 00002a1c-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470338-0600 Runner[1020:128483] uuid: 00002aea-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470458-0600 Runner[1020:128483] uuid: 00002a1e-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470594-0600 Runner[1020:128483] uuid: 00002a6e-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470716-0600 Runner[1020:128483] uuid: 00002b0d-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470834-0600 Runner[1020:128483] uuid: 00002ae2-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.470973-0600 Runner[1020:128483] uuid: 00002ae9-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.471113-0600 Runner[1020:128483] uuid: 00002bbb-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.471244-0600 Runner[1020:128483] uuid: 00002ac3-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.471383-0600 Runner[1020:128483] uuid: 00002b18-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.471499-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.471563-0600 Runner[1020:128483] service uuid:3a9057fb-6f8a-4d7e-ad45-62b1e4b2f4f3
2022-02-03 16:29:30.471634-0600 Runner[1020:128483] uuid: 398f3cff-8930-4816-836e-ff05dfd6f07d value: (null)
2022-02-03 16:29:30.471713-0600 Runner[1020:128483] uuid: fecfa698-79d8-4309-812f-179398f57a20 value: (null)
2022-02-03 16:29:30.471824-0600 Runner[1020:128483] uuid: 855076b8-beb3-4606-b351-9fc468ca3a4e value: (null)
2022-02-03 16:29:30.471929-0600 Runner[1020:128483] uuid: d5b28f7a-bc9f-49e2-a077-0803b0afd8a4 value: (null)
2022-02-03 16:29:30.472006-0600 Runner[1020:128483] uuid: 29d2887c-0746-4518-988d-77469d1bd6ae value: (null)
2022-02-03 16:29:30.472079-0600 Runner[1020:128483] uuid: 07690c5c-654c-43a7-9823-01ec5edcc7fd value: (null)
2022-02-03 16:29:30.472199-0600 Runner[1020:128483] uuid: 4c8f6845-7a7e-415f-bd54-f54d8a68be53 value: (null)
2022-02-03 16:29:30.472275-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.472338-0600 Runner[1020:128483] service uuid:3a9057fb-6f8a-4f7e-ae45-62bce4b2f4f1
2022-02-03 16:29:30.472551-0600 Runner[1020:128483] uuid: 00002b86-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.472646-0600 Runner[1020:128483] uuid: 10362b61-c775-4888-9bb2-17bec8f9e1bb value: (null)
2022-02-03 16:29:30.472722-0600 Runner[1020:128483] uuid: 198bd2ca-99b8-4e27-89d3-eab7e1389a2e value: (null)
2022-02-03 16:29:30.472808-0600 Runner[1020:128483] uuid: 00001410-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.472921-0600 Runner[1020:128483] uuid: 00001411-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.473022-0600 Runner[1020:128483] uuid: 32cf6042-f9fb-49fb-839c-93db0b591233 value: (null)
2022-02-03 16:29:30.473093-0600 Runner[1020:128483] uuid: 7c8db2c8-e8bd-4221-9c78-be516cb22991 value: (null)
2022-02-03 16:29:30.473161-0600 Runner[1020:128483] uuid: 7d311226-c6fd-4a75-8abb-41404c08b67e value: (null)
2022-02-03 16:29:30.473267-0600 Runner[1020:128483] uuid: df68adc1-3c71-4e2b-a468-90dc765b07a7 value: (null)
2022-02-03 16:29:30.473347-0600 Runner[1020:128483] uuid: f35be144-5659-4cf1-86e2-fe7d1c82de20 value: (null)
2022-02-03 16:29:30.473543-0600 Runner[1020:128483] uuid: d2ac2d86-bd61-44cc-924b-2ae2ed221680 value: (null)
2022-02-03 16:29:30.473787-0600 Runner[1020:128483] uuid: 2747a34e-e277-4510-98b0-91c176d57a61 value: (null)
2022-02-03 16:29:30.473975-0600 Runner[1020:128483] uuid: 57df3786-7b57-472b-bd5a-a4bc758952ab value: (null)
2022-02-03 16:29:30.474060-0600 Runner[1020:128483] uuid: c72e32ee-e309-4f32-b83f-8ef7e7b6f4e8 value: (null)
2022-02-03 16:29:30.474138-0600 Runner[1020:128483] uuid: d709cb47-3b4c-4f66-9588-40cd0a95d14d value: (null)
2022-02-03 16:29:30.474198-0600 Runner[1020:128483] uuid: 56eb7023-0b8b-450d-89bd-3b2881b5d327 value: (null)
2022-02-03 16:29:30.474259-0600 Runner[1020:128483] uuid: 5b6487e1-8bae-4dc1-b86a-867806a9de22 value: (null)
2022-02-03 16:29:30.474314-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.474409-0600 Runner[1020:128483] service uuid:00001805-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.474494-0600 Runner[1020:128483] uuid: 00002a2b-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.474657-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.474818-0600 Runner[1020:128483] service uuid:0000181a-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.475031-0600 Runner[1020:128483] uuid: 5e1ab631-9c07-4715-9d16-c235294cd3e6 value: (null)
2022-02-03 16:29:30.475183-0600 Runner[1020:128483] uuid: 00005501-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.475263-0600 Runner[1020:128483] uuid: 00005502-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.475338-0600 Runner[1020:128483] uuid: 00005503-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.475415-0600 Runner[1020:128483] uuid: 00008500-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.475473-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.475525-0600 Runner[1020:128483] service uuid:00001828-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.475599-0600 Runner[1020:128483] uuid: 00002add-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.475674-0600 Runner[1020:128483] uuid: 00002ade-0000-1000-8000-00805f9b34fb value: (null)
2022-02-03 16:29:30.475964-0600 Runner[1020:128483] peripheral uuid:8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.476081-0600 Runner[1020:128483] service uuid:1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0
2022-02-03 16:29:30.476153-0600 Runner[1020:128483] uuid: f7bf3564-fb6d-4e53-88a4-5e37e0326063 value: (null)
2022-02-03 16:29:30.559196-0600 Runner[1020:128483] didUpdateValueForCharacteristic 8FF8E2CD-E1FA-A880-0D3B-622622F2F7E1
2022-02-03 16:29:30.559457-0600 Runner[1020:128483] uuid: 00002a2b-0000-1000-8000-00805f9b34fb value: {length = 4, bytes = 0x393f0000}
2022-02-03 16:29:30.559665-0600 Runner[1020:128483] uuid: 00002a2b-0000-1000-8000-00805f9b34fb value: {length = 4, bytes = 0x393f0000}
2022-02-03 16:29:30.563945-0600 Runner[1020:128813] flutter: GATTdb Hash [57, 63, 0, 0]
2022-02-03 16:29:30.564119-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:30.564064 locallink
2022-02-03 16:29:30.564244-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:30.564224 Decoder
2022-02-03 16:29:30.564300-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:30.564284 DoReads
2022-02-03 16:29:30.565169-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:30.565148 ReadAll
2022-02-03 16:29:30.565943-0600 Runner[1020:128813] flutter: E: Couldn't find [00002A00] in 9 services
2022-02-03 16:29:30.566058-0600 Runner[1020:128813] flutter:   e4cf7947-ad98-425b-8f0c-571f873a88fc
2022-02-03 16:29:30.566131-0600 Runner[1020:128813] flutter:       78805e56-f8b7-4f30-a056-2ece9f4f70a9
2022-02-03 16:29:30.566280-0600 Runner[1020:128813] flutter:       665c1cbc-2c88-4ae1-9ccf-9dbc8a9e5440
2022-02-03 16:29:30.566361-0600 Runner[1020:128813] flutter:       00002ac8-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.566420-0600 Runner[1020:128813] flutter:       665c1cbc-2c88-4ae1-9ccf-9dbc8a9e5460
2022-02-03 16:29:30.566466-0600 Runner[1020:128813] flutter:       665c1cbc-2c88-4ae1-9ccf-9dbc8a988440
2022-02-03 16:29:30.566513-0600 Runner[1020:128813] flutter:       1f8783f9-06db-4982-a0ae-e78f146ec53f
2022-02-03 16:29:30.566554-0600 Runner[1020:128813] flutter:   0000180a-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.566594-0600 Runner[1020:128813] flutter:       00002a29-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.566634-0600 Runner[1020:128813] flutter:       00002a24-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.566786-0600 Runner[1020:128813] flutter:       00002a25-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.566859-0600 Runner[1020:128813] flutter:       1f8783f9-06db-4982-a0ae-e78f146ec53f
2022-02-03 16:29:30.566916-0600 Runner[1020:128813] flutter:       00002a27-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567063-0600 Runner[1020:128813] flutter:       00002a28-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567174-0600 Runner[1020:128813] flutter:       00002a23-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567236-0600 Runner[1020:128813] flutter:       00002a85-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567324-0600 Runner[1020:128813] flutter:   00001815-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567465-0600 Runner[1020:128813] flutter:       00001229-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567535-0600 Runner[1020:128813] flutter:       00001230-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567672-0600 Runner[1020:128813] flutter:       00002a1c-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567742-0600 Runner[1020:128813] flutter:       00002aea-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567792-0600 Runner[1020:128813] flutter:       00002a1e-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567850-0600 Runner[1020:128813] flutter:       00002a6e-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567892-0600 Runner[1020:128813] flutter:       00002b0d-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.567937-0600 Runner[1020:128813] flutter:       00002ae2-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.568057-0600 Runner[1020:128813] flutter:       00002ae9-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.568126-0600 Runner[1020:128813] flutter:       00002bbb-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.568176-0600 Runner[1020:128813] flutter:       00002ac3-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.568260-0600 Runner[1020:128813] flutter:       00002b18-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.568328-0600 Runner[1020:128813] flutter:   3a9057fb-6f8a-4d7e-ad45-62b1e4b2f4f3
2022-02-03 16:29:30.568446-0600 Runner[1020:128813] flutter:       398f3cff-8930-4816-836e-ff05dfd6f07d
2022-02-03 16:29:30.568519-0600 Runner[1020:128813] flutter:       fecfa698-79d8-4309-812f-179398f57a20
2022-02-03 16:29:30.568567-0600 Runner[1020:128813] flutter:       855076b8-beb3-4606-b351-9fc468ca3a4e
2022-02-03 16:29:30.568644-0600 Runner[1020:128813] flutter:       d5b28f7a-bc9f-49e2-a077-0803b0afd8a4
2022-02-03 16:29:30.568705-0600 Runner[1020:128813] flutter:       29d2887c-0746-4518-988d-77469d1bd6ae
2022-02-03 16:29:30.568863-0600 Runner[1020:128813] flutter:       07690c5c-654c-43a7-9823-01ec5edcc7fd
2022-02-03 16:29:30.568911-0600 Runner[1020:128813] flutter:       4c8f6845-7a7e-415f-bd54-f54d8a68be53
2022-02-03 16:29:30.569070-0600 Runner[1020:128813] flutter:   3a9057fb-6f8a-4f7e-ae45-62bce4b2f4f1
2022-02-03 16:29:30.569141-0600 Runner[1020:128813] flutter:       00002b86-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.569234-0600 Runner[1020:128813] flutter:       10362b61-c775-4888-9bb2-17bec8f9e1bb
2022-02-03 16:29:30.569357-0600 Runner[1020:128813] flutter:       198bd2ca-99b8-4e27-89d3-eab7e1389a2e
2022-02-03 16:29:30.569439-0600 Runner[1020:128813] flutter:       00001410-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.569509-0600 Runner[1020:128813] flutter:       00001411-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.569633-0600 Runner[1020:128813] flutter:       32cf6042-f9fb-49fb-839c-93db0b591233
2022-02-03 16:29:30.569801-0600 Runner[1020:128813] flutter:       7c8db2c8-e8bd-4221-9c78-be516cb22991
2022-02-03 16:29:30.569869-0600 Runner[1020:128813] flutter:       7d311226-c6fd-4a75-8abb-41404c08b67e
2022-02-03 16:29:30.569919-0600 Runner[1020:128813] flutter:       df68adc1-3c71-4e2b-a468-90dc765b07a7
2022-02-03 16:29:30.570168-0600 Runner[1020:128813] flutter:       f35be144-5659-4cf1-86e2-fe7d1c82de20
2022-02-03 16:29:30.570237-0600 Runner[1020:128813] flutter:       d2ac2d86-bd61-44cc-924b-2ae2ed221680
2022-02-03 16:29:30.570368-0600 Runner[1020:128813] flutter:       2747a34e-e277-4510-98b0-91c176d57a61
2022-02-03 16:29:30.570440-0600 Runner[1020:128813] flutter:       57df3786-7b57-472b-bd5a-a4bc758952ab
2022-02-03 16:29:30.570485-0600 Runner[1020:128813] flutter:       c72e32ee-e309-4f32-b83f-8ef7e7b6f4e8
2022-02-03 16:29:30.570674-0600 Runner[1020:128813] flutter:       d709cb47-3b4c-4f66-9588-40cd0a95d14d
2022-02-03 16:29:30.570743-0600 Runner[1020:128813] flutter:       56eb7023-0b8b-450d-89bd-3b2881b5d327
2022-02-03 16:29:30.570868-0600 Runner[1020:128813] flutter:       5b6487e1-8bae-4dc1-b86a-867806a9de22
2022-02-03 16:29:30.570932-0600 Runner[1020:128813] flutter:   00001805-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571072-0600 Runner[1020:128813] flutter:       00002a2b-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571139-0600 Runner[1020:128813] flutter:   0000181a-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571186-0600 Runner[1020:128813] flutter:       5e1ab631-9c07-4715-9d16-c235294cd3e6
2022-02-03 16:29:30.571222-0600 Runner[1020:128813] flutter:       00005501-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571256-0600 Runner[1020:128813] flutter:       00005502-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571292-0600 Runner[1020:128813] flutter:       00005503-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571325-0600 Runner[1020:128813] flutter:       00008500-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571362-0600 Runner[1020:128813] flutter:   00001828-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571394-0600 Runner[1020:128813] flutter:       00002add-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571426-0600 Runner[1020:128813] flutter:       00002ade-0000-1000-8000-00805f9b34fb
2022-02-03 16:29:30.571471-0600 Runner[1020:128813] flutter:   1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0
2022-02-03 16:29:30.571507-0600 Runner[1020:128813] flutter:       f7bf3564-fb6d-4e53-88a4-5e37e0326063
2022-02-03 16:29:30.571550-0600 Runner[1020:128813] flutter: E:--endofline--
2022-02-03 16:29:30.571611-0600 Runner[1020:128813] flutter: 2022-02-03 16:29:30.571572 !  BC NotFound:Name[2A00]


Android Log (I put a "Find 0xFF1F" in there to cause it to error):

I/flutter ( 7706): 2022-02-03 17:12:55.813531 going...
I/flutter ( 7706): CONNECT...
I/flutter ( 7706): 2022-02-03 17:12:55.815227 Connecting to 50:32:5F:C3:C6:3F...
I/flutter ( 7706): WannaConnect
I/flutter ( 7706): GonnaConnect
I/BluetoothAdapter( 7706): STATE_ON
D/BluetoothGatt( 7706): connect() - device: 50:32:5F:C3:C6:3F, auto: false
I/BluetoothAdapter( 7706): isSecureModeEnabled
D/BluetoothGatt( 7706): registerApp()
D/BluetoothGatt( 7706): registerApp() - UUID=1f15c6e1-c781-4f0b-b13c-77e4fe8d5f24
D/BluetoothGatt( 7706): onClientRegistered() - status=0 clientIf=14
D/BluetoothGatt( 7706): onClientConnectionState() - status=0 clientIf=14 device=50:32:5F:C3:C6:3F
I/flutter ( 7706): then
I/flutter ( 7706): return
I/flutter ( 7706): 2022-02-03 17:12:56.081445 ConnectDone
I/flutter ( 7706): !!FE - Connect isn't -- BluetoothDeviceState.disconnected
D/BluetoothGatt( 7706): discoverServices() - device: 50:32:5F:C3:C6:3F
D/BluetoothGatt( 7706): onConnectionUpdated() - Device=50:32:5F:C3:C6:3F interval=6 latency=0 timeout=500 status=0
D/BluetoothGatt( 7706): onSearchComplete() = Device=50:32:5F:C3:C6:3F Status=0
I/flutter ( 7706): GATTdb Hash [115, 73, 0, 0]
I/flutter ( 7706): E: Couldn't find [0000FF12] in 11 services
I/flutter ( 7706):   00001801-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a05-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002b2a-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002b29-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   00001800-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a00-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a01-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   e4cf7947-ad98-425b-8f0c-571f873a88fc
I/flutter ( 7706):       78805e56-f8b7-4f30-a056-2ece9f4f70a9
I/flutter ( 7706):       665c1cbc-2c88-4ae1-9ccf-9dbc8a9e5440
I/flutter ( 7706):       00002ac8-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       665c1cbc-2c88-4ae1-9ccf-9dbc8a9e5460
I/flutter ( 7706):       665c1cbc-2c88-4ae1-9ccf-9dbc8a988440
I/flutter ( 7706):       1f8783f9-06db-4982-a0ae-e78f146ec53f
I/flutter ( 7706):   0000180a-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a29-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a24-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a25-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       1f8783f9-06db-4982-a0ae-e78f146ec53f
I/flutter ( 7706):       00002a27-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a28-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a23-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a85-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   00001815-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00001229-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00001230-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a1c-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002aea-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a1e-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a6e-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002b0d-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002ae2-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002ae9-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002bbb-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002ac3-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002b18-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   3a9057fb-6f8a-4d7e-ad45-62b1e4b2f4f3
I/flutter ( 7706):       398f3cff-8930-4816-836e-ff05dfd6f07d
I/flutter ( 7706):       fecfa698-79d8-4309-812f-179398f57a20
I/flutter ( 7706):       855076b8-beb3-4606-b351-9fc468ca3a4e
I/flutter ( 7706):       d5b28f7a-bc9f-49e2-a077-0803b0afd8a4
I/flutter ( 7706):       29d2887c-0746-4518-988d-77469d1bd6ae
I/flutter ( 7706):       07690c5c-654c-43a7-9823-01ec5edcc7fd
I/flutter ( 7706):       4c8f6845-7a7e-415f-bd54-f54d8a68be53
I/flutter ( 7706):   3a9057fb-6f8a-4f7e-ae45-62bce4b2f4f1
I/flutter ( 7706):       00002b86-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       10362b61-c775-4888-9bb2-17bec8f9e1bb
I/flutter ( 7706):       198bd2ca-99b8-4e27-89d3-eab7e1389a2e
I/flutter ( 7706):       00001410-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00001411-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       32cf6042-f9fb-49fb-839c-93db0b591233
I/flutter ( 7706):       7c8db2c8-e8bd-4221-9c78-be516cb22991
I/flutter ( 7706):       7d311226-c6fd-4a75-8abb-41404c08b67e
I/flutter ( 7706):       df68adc1-3c71-4e2b-a468-90dc765b07a7
I/flutter ( 7706):       f35be144-5659-4cf1-86e2-fe7d1c82de20
I/flutter ( 7706):       d2ac2d86-bd61-44cc-924b-2ae2ed221680
I/flutter ( 7706):       2747a34e-e277-4510-98b0-91c176d57a61
I/flutter ( 7706):       57df3786-7b57-472b-bd5a-a4bc758952ab
I/flutter ( 7706):       c72e32ee-e309-4f32-b83f-8ef7e7b6f4e8
I/flutter ( 7706):       d709cb47-3b4c-4f66-9588-40cd0a95d14d
I/flutter ( 7706):       56eb7023-0b8b-450d-89bd-3b2881b5d327
I/flutter ( 7706):       5b6487e1-8bae-4dc1-b86a-867806a9de22
I/flutter ( 7706):   00001805-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002a2b-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   0000181a-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       5e1ab631-9c07-4715-9d16-c235294cd3e6
I/flutter ( 7706):       00005501-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00005502-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00005503-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00008500-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   00001828-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002add-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):       00002ade-0000-1000-8000-00805f9b34fb
I/flutter ( 7706):   1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0
I/flutter ( 7706):       f7bf3564-fb6d-4e53-88a4-5e37e0326063
I/flutter ( 7706): E:--endofline--

how to initialize ScanResults?

Whenever Bluetooth scans are performed, they are accumulating in ScanResults.
However, ScanResults is not initialized and data continues to accumulate.

How can we initialize ScanResults' data and accumulate only new data?

Getting rssi continously for scanResults?

Actually this is more like a question than an issue.

What i need to do is scan for bluetooth devices, And I periodically need to update the list with new device, and for existing device, updating their corresponding rssi in the list. For this I use Timer to execute findBluetoothPeripherial(), every 40 seconds.
My Question, is there a better way of achieving this?

FlutterBluePlus flutterBlue = FlutterBluePlus.instance;
List scanResults = <ScanResult>[];
Timer? timer;


@override
void initState(){
	super.initState();
	findBluetoothPeripherial();

	timer = Timer.periodic(Duration(seconds: 40), (Timer t) => findBluetoothPeripherial());
}


findBluetoothPeripherial(){
    //check and handle permissions
	flutterBlue.startScan(timeout: Duration(seconds: 20));

	var subscription = flutterBlue.scanResults.listen((results) {
    
	    for (ScanResult r in results) {
	        print('${r.device.name} found! rssi: ${r.rssi}');
	        int index = scanResults.indexWhere((item) => item.device.id == r.device.id);

	        if(index > 0){
	        	setState((){
		        	scanResults[index].rssi = r.rssi;
	        	});
	        }else {
	        	setState(() {
	        		scanResults.add(r);
	        	});
	        }
	    }
	});

	// Stop scanning
	flutterBlue.stopScan();
}

Another question

What is the difference between -

flutterBlue.scanResults.listen((results){
	//code here
});

And

flutterBlue.scan(timeout: Duration(seconds: 20))
        .distinct()
        .asBroadcastStream()
        .listen((results){
        		//code here
        });

Using the timeout parameter of BluetoothDevice.connect may cause two TimeoutExceptions to be thrown, one of which can't be caught

The current implementation of BluetoothDevice.connect may result in two TimeoutExceptions when the timeout parameter is not null. Try running the following code on dartpad.dev:

import 'dart:async';

Future<void> test() async {
  final completer = Completer<void>();
  Timer? timer;
  timer = Timer(Duration(seconds: 1), () {
    completer.completeError(TimeoutException('Failed to connect in time.'));
  });
  await Future.delayed(Duration(seconds: 2));
  return completer.future;
}

void main() async {
  print('Trying to catch the exception:');
  try {
    await test();
  } catch (error) {
    print(error.toString());
  }
  
  print('Usin a guarded zone:');
  runZonedGuarded(
    test,
    (error, stackTrace) {
      print(error.toString());
    },
  );
}

As you see, the test function throws two errors, one of which can only be catched using a guarded zone.

The following would be a better approach to handling timeouts:

import 'dart:async';

Future<void> test() async {
  try {
    await Future(
      () async {
        // connect to device
      },
    ).timeout(const Duration(seconds: 2));
  } on TimeoutException catch (_) {
    // disconnect device
    throw TimeoutException('Failed to connect in time.', timeout);
  }
}

void main() async {
  try {
    await test();
  } catch (_) {
    print('Handling error');
  }
}

Background scanning support?

@boskokg I've been searching for a way to do a ble scan in the background, I was using flutter_blue but that doesnt work. does this package support it? or plans to?

When to request runtime permissions? Android 12 SDK 31

EDIT: No permission reqs are actually made in my example, but it shouldn't matter because I'm not rendering anything that uses Bluetooth.

Is there a setting in flutter_blue_plus to keep it "inactive" until the moment FlutterBluePlus.instance is requested? Could be a stupid question, but here's the story:

Android 12 has turned scan, advertise, and connect into runtime permissions. However, starting my app, whose homepage does not even touch Bluetooth, gives the same error as other issues posted:

E/AndroidRuntime(17796): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.qiquacmobile/com.example.qiquacmobile.MainActivity}: java.lang.SecurityException: Permission Denial: starting Intent { act=android.bluetooth.adapter.action.REQUEST_ENABLE cmp=com.android.settings/.bluetooth.RequestPermissionActivity } from ProcessRecord{e2d3552 17796:com.example.qiquacmobile/u0a694} (pid=17796, uid=10694) requires android.permission.BLUETOOTH_CONNECT

Various sources say you need to declare these permissions in your manifest, which I have done. They also say you need to use permission_handler to request runtime permissions. Below is how I've set it up, but spoiler alert -- same error happens before the app can even open. This makes me wonder if I am misinformed about the nature of runtime permissions. Can anyone shed light on this situation?

main.dart

void main() {
  runApp(PermissionsChecker(MyApp));
}

class PermissionsChecker extends StatefulWidget {
  PermissionsChecker(this.child);
  final Widget child;

  @override
  State<PermissionsChecker> createState() => _PermissionsCheckerState();
}

class _PermissionsCheckerState extends State<PermissionsChecker> {
  // permissions (must be handled on > SDK 31 (ie. Android 12))
  bool permissionsGranted = false;

  @override
  void initState() {
    super.initState();
    checkForPermissions()
        .then((result) => setState(() => permissionsGranted = result));
  }

  /// Checks that all necessary permissions are granted to the app before
  Future<bool> checkForPermissions() async {
    PermissionStatus locStatus = await Permission.locationWhenInUse.status;
    PermissionStatus btStatus = await Permission.bluetooth.status;
    PermissionStatus btScanStatus = await Permission.bluetoothScan.status;
    PermissionStatus btConStatus = await Permission.bluetoothConnect.status;

    return false;
  }

  @override
  Widget build(BuildContext context) {
    return (permissionsGranted) // is false
        ? widget.child
        : Text('please grant permissions'); // expect this part to be rendered
  }
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // routes that need no arguments
      routes: {
        // ....
      },
      // routes that need arguments
      onGenerateRoute: (settings) {
        final args = settings.arguments;
        switch (settings.name) {
          // ... several cases

          // home page
          default:
            return MaterialPageRoute(
              settings: RouteSettings(name: r.homeRoute),
              builder: (context) => HomePage();
        }
      },
      debugShowCheckedModeBanner: false,
    );
  }
}

bottom chunk of AndroidManifest.xml

    </application>
    <!-- required for API 18 - 30 -->
    <uses-permission
            android:name="android.permission.BLUETOOTH"
            android:maxSdkVersion="30" />
    <uses-permission
            android:name="android.permission.BLUETOOTH_ADMIN"
            android:maxSdkVersion="30" />

    <!-- required for API 23 - 30 -->
    <uses-permission-sdk-23
            android:name="android.permission.ACCESS_COARSE_LOCATION"
            android:maxSdkVersion="30" />
    <uses-permission-sdk-23
            android:name="android.permission.ACCESS_FINE_LOCATION"
            android:maxSdkVersion="30" />

    <!-- API 31+ -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission
            android:name="android.permission.BLUETOOTH_SCAN"
            android:usesPermissionFlags="neverForLocation" />
</manifest>

Disconnected issue in iOS

When device is disconnected (not manually) instead of sending a 'disconnect' event, a 'connecting' event is sent.

cannot get indicate value listener

for my module, i first need to write to first characteristic, follow by set second characteristic indicate to true, and listen to the indicate return value. But i failed to get the return value.

Not find device

I have a device and i can see it by bluetooth of mobile but i can no see it by this plugin

I can't disconnect the device from the connected device if the app restarts

Scenario 0

connect to some device
disconnect above device
-----> doing well

■ Scenario 1

connect to some device
terminate app
restart app
-----> we can find connected device by
-----> listening connectedDeviceStream

How can i disconnect device what found by connectedDeviceStream
not from manually connectToDevice nor connectToAdvertisingDevice ?

i already know canceling stream from connectToDevice
or connectToAdvertisingDevice take disconnection

but, connected device from connectedDeviceStream have no stream
so i can't disconenct those devices..... T_T

■ Trying
after Scenario 1, if i found already connected device
then make connection and cancel...

but can't get disconnected callback by ConnectionStateUpdate
(both stream from connection and FlutterReactiveBle.instants's connectedDeviceStream)

also can't scan that device...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.