Add auto-connect support (#206)

* Add autoConnect support

* Enhance autoConnect functionality for Bluetooth devices

- Added support for managing a set of auto-connect devices in both Android and iOS implementations.
- Updated connection and disconnection logic to handle auto-reconnect scenarios appropriately.
- Improved cleanup processes to prevent unwanted reconnections when devices are manually disconnected.

* Refactor connection button and add auto-reconnect toggle

- Updated the connection button layout for better UI consistency.
- Introduced an auto-reconnect toggle to manage automatic reconnections when devices become available.
- Enhanced connection and disconnection logic to respect the auto-connect setting.

* Update version to 1.2.0 and add CHANGELOG for new features

- Bumped version to 1.2.0.
- Added CHANGELOG.md detailing new features including support for `autoConnect` and UI updates for automatic reconnection.

* Improve readme

* Refactor variable naming for clarity in Bluetooth connection logic

- Changed variable name from `isAutoConnect` to `shouldAutoConnect` for better readability and understanding of its purpose in the connection state handling.

* Refactor connection handling in UniversalBlePlugin

- Simplified connection logic by always cleaning up internal state before sending connection change callbacks.
- Ensured GATT resources are only closed when autoConnect is disabled, allowing for better management of Bluetooth connections.

* Refactor disconnection handling in UniversalBlePlugin

- Introduced a new method `handlePeripheralDisconnection` to encapsulate disconnection logic, improving code readability and maintainability.
- Updated the `centralManager` methods to utilize the new disconnection handler, ensuring consistent behavior across connection state changes.

* Update darwin/Classes/UniversalBlePlugin.swift

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Foti Dim <fotios.dimanidis@a2zebra.de>
Co-authored-by: Navideck Labs <130186950+navidecklabs@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Foti Dim
2026-01-16 07:06:24 +01:00
committed by GitHub
parent a30e84a70c
commit 8557a46d05
28 changed files with 323 additions and 106 deletions
+3 -1
View File
@@ -17,7 +17,9 @@ extension BleDeviceExtension on BleDevice {
BleConnectionState.connected;
/// Connects to the device.
Future<void> connect() => UniversalBle.connect(deviceId);
/// [autoConnect] enables automatic reconnection when the device becomes available.
Future<void> connect({bool autoConnect = false, Duration? timeout}) =>
UniversalBle.connect(deviceId, autoConnect: autoConnect, timeout: timeout);
/// Disconnects from the device.
Future<void> disconnect() => UniversalBle.disconnect(deviceId);
+22 -10
View File
@@ -134,16 +134,26 @@ class UniversalBle {
/// It is advised to stop scanning before connecting.
/// It throws error if device connection fails.
/// Default connection timeout is 60 sec.
///
/// [autoConnect] enables automatic reconnection when the device becomes available.
/// Default value is `false`.
/// Ignored on `Windows`, `Linux` and `Web`.
///
/// Call [disconnect] to prevent auto-reconnect even while a device is disconnected.
///
/// Can throw `ConnectionException` or `PlatformException`.
static Future<void> connect(
String deviceId, {
Duration? timeout,
bool autoConnect = false,
}) async {
timeout ??= const Duration(seconds: 60);
Completer<bool> completer =
_connectionEventCompleter(deviceId, timeout: timeout);
_platform.connect(deviceId, connectionTimeout: timeout).catchError(
_platform
.connect(deviceId, connectionTimeout: timeout, autoConnect: autoConnect)
.catchError(
(error) {
if (completer.isCompleted) return;
completer.completeError(ConnectionException(error));
@@ -169,15 +179,6 @@ class UniversalBle {
UniversalLogger.logError("Get connection state failed: $e");
}
if (connectionState == BleConnectionState.disconnected ||
connectionState == BleConnectionState.disconnecting) {
_platform.updateConnection(deviceId, false);
UniversalLogger.logInfo(
"Device $deviceId already disconnected: $connectionState",
);
return;
}
try {
Completer<bool> completer =
_connectionEventCompleter(deviceId, timeout: timeout);
@@ -192,6 +193,17 @@ class UniversalBle {
},
);
if (connectionState == BleConnectionState.disconnected ||
connectionState == BleConnectionState.disconnecting) {
// Device was already disconnected, but we still called platform disconnect
// to prevent auto-reconnect. Update connection state and return.
_platform.updateConnection(deviceId, false);
UniversalLogger.logInfo(
"Device $deviceId already disconnected: $connectionState. Cleanup performed to prevent auto-reconnect.",
);
return;
}
if (await completer.future.timeout(timeout)) {
UniversalLogger.logError(
"Device $deviceId is still connected after disconnect attempt",
@@ -141,7 +141,8 @@ class UniversalBleLinux extends UniversalBlePlatform {
}
@override
Future<void> connect(String deviceId, {Duration? connectionTimeout}) async {
Future<void> connect(String deviceId, {Duration? connectionTimeout, bool autoConnect = false}) async {
// Note: autoConnect is not directly supported on Linux platform
final device = _findDeviceById(deviceId);
if (device.connected) {
updateConnection(deviceId, true);
@@ -776,7 +776,7 @@ class UniversalBlePlatformChannel {
}
}
Future<void> connect(String deviceId) async {
Future<void> connect(String deviceId, {bool? autoConnect}) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
@@ -785,7 +785,7 @@ class UniversalBlePlatformChannel {
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
pigeonVar_channel.send(<Object?>[deviceId, autoConnect]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
@@ -69,8 +69,8 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
}
@override
Future<void> connect(String deviceId, {Duration? connectionTimeout}) =>
_executeWithErrorHandling(() => _channel.connect(deviceId));
Future<void> connect(String deviceId, {Duration? connectionTimeout, bool autoConnect = false}) =>
_executeWithErrorHandling(() => _channel.connect(deviceId, autoConnect: autoConnect));
@override
Future<void> disconnect(String deviceId) =>
@@ -53,7 +53,7 @@ abstract class UniversalBlePlatform {
Future<bool> isScanning();
Future<void> connect(String deviceId, {Duration? connectionTimeout});
Future<void> connect(String deviceId, {Duration? connectionTimeout, bool autoConnect = false});
Future<void> disconnect(String deviceId);
@@ -35,7 +35,9 @@ class UniversalBleWeb extends UniversalBlePlatform {
Future<void> connect(
String deviceId, {
Duration? connectionTimeout = const Duration(seconds: 10),
bool autoConnect = false,
}) async {
// Note: autoConnect is not directly supported on Web platform
var device = _getDeviceById(deviceId);
if (device == null) {
throw UniversalBleException(