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:
@@ -0,0 +1,8 @@
|
||||
## 1.1.0
|
||||
* Add support for `autoConnect` parameter
|
||||
* Display RSSI values in device details
|
||||
* Persist filters
|
||||
* Fix clear log button
|
||||
|
||||
## 1.0.0
|
||||
* Initial release
|
||||
@@ -52,7 +52,7 @@ class MockUniversalBle extends UniversalBlePlatform {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect(String deviceId, {Duration? connectionTimeout}) async {
|
||||
Future<void> connect(String deviceId, {bool autoConnect = false, Duration? connectionTimeout}) async {
|
||||
updateConnection(deviceId, true);
|
||||
_connectionStateMap[deviceId] = BleConnectionState.connected;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class _AppDrawerState extends State<AppDrawer> {
|
||||
applicationName: 'Universal BLE',
|
||||
applicationVersion:
|
||||
"${snapshot.data?.version} (${snapshot.data?.buildNumber})",
|
||||
applicationLegalese: '\u{a9} 2025 Navideck',
|
||||
applicationLegalese: '\u{a9} 2023 Navideck',
|
||||
aboutBoxChildren: [
|
||||
const SizedBox(height: 24),
|
||||
RichText(
|
||||
|
||||
@@ -32,6 +32,7 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
bool _isDeviceInfoExpanded = false;
|
||||
bool _isDeviceActionsExpanded = true;
|
||||
final Map<String, bool> _subscribedCharacteristics = {};
|
||||
bool _autoConnect = false;
|
||||
|
||||
StreamSubscription? connectionStreamSubscription;
|
||||
StreamSubscription? pairingStateSubscription;
|
||||
@@ -688,59 +689,155 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
|
||||
Widget _buildConnectDisconnectButton() {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
if (isConnected) {
|
||||
await _executeWithLoading(
|
||||
() async {
|
||||
await bleDevice.disconnect();
|
||||
_addLog("DisconnectResult", true);
|
||||
},
|
||||
onError: (error) {
|
||||
_addLog('DisconnectError', error);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _executeWithLoading(
|
||||
() async {
|
||||
await bleDevice.connect();
|
||||
_addLog("ConnectionResult", true);
|
||||
},
|
||||
onError: (error) {
|
||||
_addLog(
|
||||
'ConnectError (${error.runtimeType})',
|
||||
error,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
isConnected ? Icons.bluetooth_disabled : Icons.bluetooth_connected,
|
||||
size: 20,
|
||||
),
|
||||
label: Text(isConnected ? 'Disconnect' : 'Connect'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isConnected ? colorScheme.error : colorScheme.primary,
|
||||
foregroundColor:
|
||||
isConnected ? colorScheme.onError : colorScheme.onPrimary,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16,
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// AutoConnect toggle
|
||||
Card(
|
||||
elevation: 1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 2,
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.autorenew,
|
||||
size: 18,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Auto Reconnect',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Automatically reconnect when device becomes available',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: _autoConnect,
|
||||
onChanged: (value) async {
|
||||
// If toggling off auto-connect, disconnect to prevent unwanted reconnections
|
||||
if (!value && _autoConnect) {
|
||||
if (isConnected) {
|
||||
// Device is connected, disconnect it to prevent auto-reconnect
|
||||
await _executeWithLoading(
|
||||
() async {
|
||||
await bleDevice.disconnect();
|
||||
_addLog("DisconnectResult",
|
||||
"Disconnected to disable auto-reconnect");
|
||||
},
|
||||
onError: (error) {
|
||||
_addLog('DisconnectError', error);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Device is already disconnected, but call disconnect() anyway
|
||||
// to ensure cleanup and prevent any pending auto-reconnection attempts
|
||||
await _executeWithLoading(
|
||||
() async {
|
||||
await bleDevice.disconnect();
|
||||
_addLog("DisconnectResult",
|
||||
"Cleanup performed to prevent auto-reconnect");
|
||||
},
|
||||
onError: (error) {
|
||||
_addLog('DisconnectError', error);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
_autoConnect = value;
|
||||
});
|
||||
},
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Connect/Disconnect button
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
if (isConnected) {
|
||||
await _executeWithLoading(
|
||||
() async {
|
||||
await bleDevice.disconnect();
|
||||
_addLog("DisconnectResult", true);
|
||||
},
|
||||
onError: (error) {
|
||||
_addLog('DisconnectError', error);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _executeWithLoading(
|
||||
() async {
|
||||
await bleDevice.connect(autoConnect: _autoConnect);
|
||||
_addLog(
|
||||
"ConnectionResult",
|
||||
"Connected${_autoConnect ? ' (Auto-reconnect enabled)' : ''}",
|
||||
);
|
||||
},
|
||||
onError: (error) {
|
||||
_addLog(
|
||||
'ConnectError (${error.runtimeType})',
|
||||
error,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
isConnected
|
||||
? Icons.bluetooth_disabled
|
||||
: Icons.bluetooth_connected,
|
||||
size: 20,
|
||||
),
|
||||
label: Text(isConnected ? 'Disconnect' : 'Connect'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isConnected ? colorScheme.error : colorScheme.primary,
|
||||
foregroundColor:
|
||||
isConnected ? colorScheme.onError : colorScheme.onPrimary,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'package:universal_ble_example/home/scanner_screen.dart';
|
||||
Future<bool> initializeApp() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await StorageService.instance.init();
|
||||
// await UniversalBle.setLogLevel(BleLogLevel.verbose);
|
||||
await UniversalBle.setLogLevel(BleLogLevel.verbose);
|
||||
return await UniversalBle.hasPermissions(
|
||||
withAndroidFineLocation: false,
|
||||
);
|
||||
|
||||
@@ -11,4 +11,4 @@ PRODUCT_NAME = Universal BLE
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.navideck.universalble
|
||||
|
||||
// The copyright displayed in application information
|
||||
PRODUCT_COPYRIGHT = Copyright © 2025 com.navideck. All rights reserved.
|
||||
PRODUCT_COPYRIGHT = Copyright © 2023 com.navideck. All rights reserved.
|
||||
|
||||
@@ -18,12 +18,12 @@ package_rename_config:
|
||||
macos:
|
||||
app_name: "Universal BLE"
|
||||
package_name: "com.navideck.universalble"
|
||||
copyright_notice: "Copyright © 2025 com.navideck. All rights reserved."
|
||||
copyright_notice: "Copyright © 2023 com.navideck. All rights reserved."
|
||||
|
||||
windows:
|
||||
app_name: "Universal BLE"
|
||||
organization: "Navideck"
|
||||
copyright_notice: "Copyright © 2025 com.navideck. All rights reserved."
|
||||
copyright_notice: "Copyright © 2023 com.navideck. All rights reserved."
|
||||
exe_name: "universal_ble"
|
||||
|
||||
web:
|
||||
|
||||
@@ -93,7 +93,7 @@ BEGIN
|
||||
VALUE "FileDescription", "Universal BLE" "\0"
|
||||
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
||||
VALUE "InternalName", "Universal BLE" "\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2025 com.navideck. All rights reserved." "\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2023 com.navideck. All rights reserved." "\0"
|
||||
VALUE "OriginalFilename", "universal_ble.exe" "\0"
|
||||
VALUE "ProductName", "Universal BLE" "\0"
|
||||
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
||||
|
||||
Reference in New Issue
Block a user