flutter_splendid_ble 1.7.0
flutter_splendid_ble: ^1.7.0 copied to clipboard
A comprehensive Flutter plugin for interacting with Bluetooth Low Energy (BLE) devices.
Changelog #
All notable changes to the flutter_splendid_ble plugin will be documented in this file.
1.7.0 - 2026-11-02 #
- Fixed BLE operations silently stopping each other's event streams
- All central callbacks share one native method channel. Previously, every
startScan,connect,observeConnectionState,discoverServices,observeBondState,readCharacteristic,emitCurrentBluetoothStatus, andemitCurrentPermissionStatuscall replaced a single shared callback handler, so the stream returned by the previous call stopped receiving events without an error or done event - Native callbacks are now delivered to every stream that matches them, the same way characteristic notifications already were. For example, an adapter status stream keeps reporting after a scan starts, a connection stream for one device keeps reporting after connecting to another device, and a running scan keeps delivering results during a concurrent connect or service discovery
readCharacteristicnow completes only with the read response matching its characteristic's device address and UUID (ignoring case), so concurrent reads no longer interfere with each other. Its listener is released when the read succeeds, fails, or times out- Malformed service discovery payloads are now emitted as stream errors instead of being thrown inside the method channel handler
- All central callbacks share one native method channel. Previously, every
- Fixed Android scanning and connections failing for the life of the app process when Bluetooth was off as the plugin started
- The plugin previously cached the
BluetoothLeScannerwhen attaching to the Flutter engine. Android provides no scanner while Bluetooth is off, so plugin startup failed partway, and every later scan, connection, and permission request failed until the process was killed, even after Bluetooth was turned on - The scanner is now looked up each time a scan starts or stops, and the plugin only begins answering calls from Dart once it has finished initializing
startScannow throws aBluetoothScanExceptionwhen the scan cannot be started, for example on Android while Bluetooth is turned off. Previously, this surfaced as a rawPlatformExceptionfrom an unhandled native exception
- The plugin previously cached the
- Fixed iOS and macOS not reporting Bluetooth adapter and permission changes to existing status streams
- iOS previously sent only permission status when CoreBluetooth's state changed, so streams from
emitCurrentBluetoothStatusnever learned that Bluetooth had been turned on or off after they were created. macOS had the opposite gap and never pushed permission changes - Both platforms now push adapter status and permission status whenever CoreBluetooth reports a state change, matching Android. On iOS this also corrects an early "disabled" status reported before CoreBluetooth finishes initializing
- iOS previously sent only permission status when CoreBluetooth's state changed, so streams from
- Scan results now update when a device's advertised content changes
- Previously, each device was emitted once per scan session, and every later advertisement from it was dropped on all platforms. A device first seen with incomplete data (for example, before its scan response arrived) stayed incomplete for the whole scan, and changes to its advertised data were never reported
- A device is now emitted again whenever its name, manufacturer data, or advertised service UUIDs change during the scan, so scan streams can contain the same address more than once. Use the latest emission for an address as its current state
- Changes in RSSI alone are not emitted
- A result that omits a field, such as an advertisement received without its scan response, keeps the value last emitted for that field, so partial packets do not replace complete data
- Corrected the
ScanSettings.allowDuplicatesdocumentation, which described the setting backwards. On iOS and macOS,truemakes CoreBluetooth deliver every advertisement, so content changes are noticed promptly; when unset orfalse, CoreBluetooth coalesces repeat advertisements and later changes may be noticed late or not at all. The setting has no effect on Android, which always delivers repeat advertisements
Known Limitations #
- Some native failures are reported with an untargeted
errorcallback that identifies neither a device nor an operation. These errors are delivered only to the stream of the most recently started scan, connection, connection observation, service discovery, or bond observation, as before. Adapter status, permission status, and characteristic read calls no longer take over delivery of these errors
1.6.0 - 2026-10-25 #
- Cross-platform bonding (pairing) diagnostics
- Added
SplendidBleCentral.observeBondState, returning aFuture<Stream<BleBondEvent>>that reports the operating-system-managed bonding process for a peripheral - Bonding is performed by the OS, not by the plugin;
observeBondStatedoes not initiate a bond, it surfaces the bond-state transitions the OS exposes so apps can show pairing progress and diagnose pairing failures BleBondEventpairs aBleBondState(none,bonding,bonded,failed,unknown) with optional failure detail- A failed bond attempt carries a
BleBondFailuredescribing why it failedcategoryis a normalized, platform-agnosticBleBondFailureCategory(authenticationFailure,authenticationRejected,authenticationTimeout,remoteDeviceDown,removed,unknown) intended for writing recovery logic once across platformsplatform,rawCode,domain, anddescriptionpreserve the raw platform-specific detail for logging and diagnosis
- Android subscribes to the
ACTION_BOND_STATE_CHANGEDbroadcast, emits the current bond state immediately on subscription, and normalizes the unbond reason code into the shared category set on failure
- Added
Known Limitations #
- iOS and macOS bonding visibility is best-effort and far coarser than Android's, because CoreBluetooth exposes no bonding API, bond-state callback, or bonding failure reason to apps. This is a platform restriction imposed by the operating system, not a limitation of this plugin. On these platforms
observeBondStatederives updates from the lifecycle of operations on encrypted characteristics: it emits an initialunknown(the real bond state cannot be read),bondingwhen an acknowledged write to an observed device begins,bondedwhen it succeeds, andfailedwith whateverCBATTError/CBErrordetail is available when it fails with an authentication/encryption error. In practice the iOS/macOS failurecategoryresolves toauthenticationFailureorunknown.
1.5.0 - 2026-10-24 #
- Characteristic notification streams now isolate updates by device address and characteristic UUID, ignoring case.
- Notification streams retain their shared native receiver when another subscription or BLE operation installs or clears a callback handler. Cancelling one stream listener does not interrupt other characteristic listeners.
- Rich, cross-platform connection error reporting
- Connection streams now emit
BleConnectionEventobjects that pair the connection state with optional failure detail, rather than a bareBleConnectionState - Connection failures and unexpected disconnections now carry a
BleConnectionFailuredescribing why the attempt failed or the link was lostcategoryis a normalized, platform-agnosticBleConnectionFailureCategory(timeout,peerTerminated,hostTerminated,authenticationFailure,connectionLimitReached,unreachable,unknown) intended for writing recovery logic once across all platformsplatform,rawCode,domain, anddescriptionpreserve the raw platform-specific detail for logging and diagnosis
- iOS and macOS now forward the
NSErrorfromdidFailToConnectanddidDisconnectPeripheral(code, domain, andlocalizedDescription), normalizingCBErrorandCBATTErrorcodes into the shared category set - Android now forwards the GATT/HCI status code from
onConnectionStateChange, normalizing common status codes (such as 8, 19, 22) into the shared category set, and distinguishes a failed connection attempt from an unexpected disconnection of an established link - Added a new
BleConnectionState.failedvalue, distinct fromdisconnected, representing a connection attempt that never succeeded
- Connection streams now emit
- Bug fixes to connection state parsing
- Fixed a crash where a
"FAILED"connection status emitted by iOS and macOS had no correspondingBleConnectionStatevalue, causing the Dart method channel handler to throw aStateError - Connection state parsing is now tolerant of unrecognized values, resolving them to
BleConnectionState.unknowninstead of throwing; this also fixes a case-sensitivity mismatch ingetCurrentConnectionState
- Fixed a crash where a
Breaking Changes #
SplendidBleCentral.connectandSplendidBleCentral.observeConnectionStatenow returnFuture<Stream<BleConnectionEvent>>instead ofFuture<Stream<BleConnectionState>>. Listeners that previously received aBleConnectionStatenow receive aBleConnectionEvent; read the connection state fromevent.stateand the failure detail (when present) fromevent.failure. Apps that do not need the richer error detail can remain on 1.5.x.- The native method channel payload for connection updates changed from a bare status string to a map. This affects only code that bypasses the plugin's Dart API to listen on the
bleConnectionState_<address>method channel directly.
1.4.0 - 2026-09-01 #
- Made macOS characteristic writes with response truly asynchronous
writeCharacteristicwith write type.withResponsenow defers the DartFutureuntil CoreBluetooth'sdidWriteValueForcallback confirms the ATT write response- This ensures
awaitcorrectly waits for encrypted characteristic writes, where CoreBluetooth initiates pairing first and retries the write only after the bond is established - Writes without response continue to resolve immediately, since no acknowledgement is sent
- Pending writes are now failed cleanly if the device disconnects mid-operation, preventing the Dart
Futurefrom hanging indefinitely
- Migrated to Android Gradle Plugin 9+
- Updated AGP to 9.0.1 and Kotlin to 2.3.20 in the example and test apps
- Updated the Gradle wrapper to 9.1.0
- Simplified and modernized the plugin's
android/build.gradleconfiguration
- Documentation formatting cleanup
1.3.3 - 2026-07-28 #
- Removed
maxSdkVersion="30"restriction from location permissions in the Android manifestACCESS_COARSE_LOCATIONandACCESS_FINE_LOCATIONare no longer capped at API 30- Fixes BLE scanning issues on devices where the system requires location permissions regardless of Android version
1.3.2 - 2026-07-25 #
- Automatic GATT cache refresh on Android for bonded devices during reconnection
- When reconnecting to a previously bonded device, the plugin now calls
BluetoothGatt.refresh()to clear the local attribute cache before proceeding with MTU negotiation - This prevents stale cached service/characteristic handles from causing connection failures when a peripheral's GATT table has changed between sessions
- A 300ms delay is applied after the cache refresh to allow the Bluetooth stack to complete the internal invalidation before issuing GATT operations
- Non-bonded connections are unaffected and proceed immediately without delay
- When reconnecting to a previously bonded device, the plugin now calls
1.3.1 - 2026-07-25 #
- Added a comment on the Android side documenting how to clear the GATT cache
1.3.0 - 2026-07-23 #
- Added Swift Package Manager support for iOS and macOS platforms
- Created
Package.swiftmanifests for both iOS (targeting iOS 13.0) and macOS (targeting macOS 10.15) - Migrated Swift source files to SPM-compatible directory structure (
flutter_splendid_ble/Sources/flutter_splendid_ble/) - Updated CocoaPods podspec files to reference the new source paths
- Plugin now supports both Swift Package Manager and CocoaPods for backward compatibility
- Created
1.2.0 - 2026-06-25 #
- Improved Android BLE connection reliability to reduce GATT_ERROR (status 133) failures
connect()now closes any existing GATT client for the same device before opening a new one, preventing native GATT slot leaks during rapid reconnect cyclesconnect()handles null return fromconnectGatt(), which can occur on some OEMs when the BLE stack is exhaustedonConnectionStateChangenow verifies GATT instance identity, preventing stale callbacks from a previous connection attempt from interfering with a new connection
disconnect()is now a true asynchronous operation on Android- The Dart
Futurereturned bydisconnect()no longer resolves until the full disconnect lifecycle completes (physical disconnection handshake, GATT close, and native resource release) - A 1.5-second fallback timer ensures the
Futurealways resolves even if the BLE stack becomes unresponsive - This allows Flutter code to safely
await disconnect()before starting a new connection
- The Dart
- Unified manufacturer data format across Android and iOS
Breaking Changes #
- Android manufacturer data now includes the vendor ID bytes as a prefix, matching the existing iOS behavior. Previously, Android omitted the vendor ID from the complete manufacturer data payload. Code that parses manufacturer data by byte index may need to be updated to account for the two additional leading bytes.
1.1.0 - 2026-06-05 #
- Added support for requesting preferred PHY (physical layer) for BLE connections
- New
requestPreferredPhymethod supports LE 1M, LE 2M, and LE Coded PHYs - Implemented on Android (API 26+); no-op on iOS and macOS where the OS manages PHY selection
- New
- Added support for requesting connection priority (connection interval)
- New
requestConnectionPrioritymethod withbalanced,high, andlowPoweroptions - Useful for maximising throughput before large data transfers like OTA firmware updates
- Implemented on Android; no-op on iOS and macOS
- New
- Added ability to read active BLE connection parameters
- New
readConnectionParametersmethod returns TX/RX PHY, connection interval, slave latency, and supervision timeout - Available on Android API 26+; returns null on iOS and macOS
- New
- Added new models:
BlePhy,BleConnectionPriority, andBleConnectionParameters - Improved scan response handling on Android
- Enhanced
BleScannerHandlerto better handle devices that split advertisement data across multiple packets - Added
legacyModeoption toScanSettingsfor controlling extended advertising PDU support on Android 8+
- Enhanced
- Improved scan response handling on iOS and macOS
- Added fallback timeout mechanism for connectable devices whose scan response may not arrive
- Buffered advertisements are now flushed when a scan session ends or restarts, ensuring no devices are silently dropped
- Updated advertisement data handling on iOS and macOS for more reliable manufacturer data reporting
- Updated write operations to support duration measurement
- Added
completeDatagetter toManufacturerDatafor accessing full manufacturer data including ID and payload - Updated Android
compileSdkto 35 and Kotlin to 2.1.0 - Updated Android Gradle plugin to 8.7.3
- Updated fake/mock method channel with implementations for new PHY and connection priority methods
- Added notification characteristic to ESP32 test firmware
- Added dynamic security characteristic to ESP32 test firmware
- Added ability to copy test results in the test app
- Code cleanup and formatting improvements
0.1.0 - 2023-10-07 #
- Initial support for Bluetooth operations on Android:
- Bluetooth status checking.
- Emitting current Bluetooth status.
- Bluetooth device scanning.
- Bluetooth device connection handling.
- Bluetooth service and characteristic discovery and subscription.
- Reading from Bluetooth characteristics.
- Writing to Bluetooth characteristics.
- Terminating a connection to a BLE device.
- Android example application to demonstrate basic usage.
- Comprehensive documentation for Android functionality.
0.2.0 - 2023-11-02 #
- Finalized support for Android.
- Added support for Bluetooth operations MacOS:
- Bluetooth status checking.
- Emitting current Bluetooth status.
- Bluetooth device scanning.
- Bluetooth device connection handling.
- Bluetooth service and characteristic discovery and subscription.
- Reading from Bluetooth characteristics.
- Writing to Bluetooth characteristics.
- Terminating a connection to a BLE device.
- Added MacOS support to the example application.
- Comprehensive documentation for MacOS functionality.
- Added automated test for all plugin methods.
0.3.0 - 2023-11-07 #
- Added support for Bluetooth operations on iOS:
- Bluetooth status checking.
- Emitting current Bluetooth status.
- Bluetooth device scanning.
- Bluetooth device connection handling.
- Bluetooth service and characteristic discovery and subscription.
- Reading from Bluetooth characteristics.
- Writing to Bluetooth characteristics.
- Terminating a connection to a BLE device.
- Added iOS support to the example application.
- Comprehensive documentation for iOS functionality.
- Added extensive usage/tutorials content to README.
0.4.0 - 2023-11-08 #
- Fixed linter issues
- Updated documentation, especially around handling of streams
0.4.1 - 2023-11-08 #
- Cosmetic updates to README
0.4.2 - 2023-11-08 #
- README updates
0.5.0 - 2023-11-17 #
- Updated example app
- Wrote extensive tutorial article
0.6.0 - 2023-12-16 #
- Updated dependencies
- Updated scan filtering by UUID
0.7.0 - 2023-01-11 #
- Updated dependencies
- Updated documentation
- Updated formatting to meet Dart standards
0.8.0 - 2023-01-15 #
- Clear scan results when restarting BLE scan
- Updated documentation for example app
0.9.0 - 2024-05-23 #
- Updated Bluetooth permissions handling process
- Updated documentation
0.10.0 - 2024-05-24 #
- Re-formatted project according to Dart standards
0.11.0 - 2024-05-31 #
- Added ability to filter scans by service UUIDs on macOS
- Added content to the README about configuring and requesting permissions
0.11.1 - 2024-06-02 #
- Updated Dartdoc references
0.11.2 - 2024-06-11 #
- Updated documentation
0.11.3 - 2024-06-14 #
- Updated documentation
0.12.0 - 2024-08-24 #
- Updated lint rules for example
- Updated lint rules for plugin
- Updated documentation
- Updated characteristic interaction UI
0.13.0 - 2024-08-31 #
- Added method to get connected Bluetooth devices (currently only for iOS and macOS)
0.14.0 - 2025-01-25 #
- Created a new documentation site using Docusaurus: https://splendid-ble.web.app/
- Updated handling of scan filters on Android
0.15.0 - 2025-02-10 #
- Added support for scanning BLE peripherals capable of accepting scan requests. Devices like this may spread their advertising data over multiple packets. This change allows app using this plugin to get the full data for this type of device.
- Updated documentation
Breaking Changes #
- Manufacturer data for the
BleDeviceclass is now represented by a custom class rather than a string; this is theManufacturerDataclass.- If you wish to continue using the manufacturer data as a string, you can use
manufacturerData.payloadto get the raw data.
- If you wish to continue using the manufacturer data as a string, you can use
0.16.0 - 2025-04-07 #
- Added support for scanning BLE peripherals capable of accepting scan requests on macOS platforms.
0.16.1 - 2025-04-19 #
- Updated Android Gradle plugin version and dependencies
0.16.2 - 2025-06-14 #
- Updated example app localization dependencies
- Fixed scan filtering by UUID for Android
0.17.0 - 2025-06-29 #
- Updated filtering devices by name
- Updated filtering devices by vendor ID
- Updated filtering devices by manufacturer data
- Added Bluetooth mocking tools for testing purposes
- Added integration tests for the example app as references
0.18.0 - 2025-09-23 #
- Updated Method Channel calls to be asynchronous
- Async Method Channel calls allow for more robust error handling
0.19.0 - 2025-11-28 #
- Implemented native Android Bluetooth permission handling
- Added
BluetoothPermissionsHandlerclass for Android platform - Automatic permission selection based on Android version (API 23-34)
- Android 12+ (API 31+): Requests BLUETOOTH_SCAN and BLUETOOTH_CONNECT permissions
- Android 10-11 (API 29-30): Requests ACCESS_FINE_LOCATION permission
- Android 6-9 (API 23-28): Requests ACCESS_FINE_LOCATION permission
- Added
- Fixed
MissingPluginExceptionforrequestBluetoothPermissionsandemitCurrentPermissionStatuson Android - Updated
FlutterSplendidBlePluginto implementActivityAwarefor proper permission request handling - Fixed race condition in permission status emission to ensure listeners receive initial values
- Updated AndroidManifest.xml with version-specific permission declarations
- Updated example app to demonstrate proper permission request flow
- Added unit tests for permission methods
Breaking Changes #
- Android apps must now declare Bluetooth permissions in their AndroidManifest.xml (see documentation)
0.20.0 - 2025-12-30 #
- Enhanced Android BLE write operations with improved reliability and asynchronous handling
- Implemented sequential write operation queue to prevent race conditions
- Added completion feedback for successful write operations
- Updated Method Channel to return results after write operations complete
- Improved error handling for Android API 33+
- Fixed UUID filtering for BLE device scanning on Android
- Fixed service UUID reporting accuracy on iOS
- Code cleanup and optimization for better performance
- Updated documentation for improved clarity
1.0.0 - 2026-01-22 #
Platform Synchronization #
- Synchronized BLE APIs across Android, iOS, and macOS platforms for consistent behavior
- Unified scan response handling across all platforms
- Standardized manufacturer data reporting format
- Consistent UUID filtering implementation delegated to Dart layer for cross-platform reliability
- Updated iOS scan response handling to properly aggregate advertising and scan response data
- Improved macOS deployment target compatibility
Enhanced BLE Operations #
- Implemented MTU negotiation immediately after connection establishment for optimal data transfer
- Added support for characteristic indications in addition to notifications
- Enhanced descriptor write operations with proper completion awaiting
- Improved subscription/unsubscription reliability with confirmation waiting
- Added method to monitor device connection state changes in real-time
- Enhanced disconnect handling and connection state management
Testing Infrastructure #
- Created comprehensive ESP32-based BLE test device firmware for hardware-in-the-loop testing
- Implements multiple test characteristics (read, write, notify, indicate, encrypted, MITM)
- Provides manufacturer data in both advertisement and scan response packets
- Visual feedback via LED matrix for connection status
- Standardized test service with known UUIDs for validation
- Developed dedicated test application for systematic BLE functionality validation
- Automated test suite covering all plugin capabilities
- Real-time test result reporting with pass/fail indicators
- Tests for scanning, connection, service discovery, read/write operations, notifications, and pairing
- Cross-platform validation (Android, iOS, macOS)
- Added Makefile commands for firmware building and flashing
- Integrated ESP32 test firmware as Git submodule
Reliability Improvements #
- Enhanced permission and adapter status checking logic
- Improved error handling throughout the plugin
- Code cleanup and optimization across all platform implementations
- Better handling of edge cases in BLE operations
Developer Experience #
- Comprehensive hardware-in-the-loop testing capability
- Clear visual feedback for test results
- Detailed logging for debugging
- Improved documentation for testing procedures
Breaking Changes #
None - this release maintains backward compatibility with 0.x versions while adding new capabilities.