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:
@@ -517,7 +517,7 @@ interface UniversalBlePlatformChannel {
|
||||
fun startScan(filter: UniversalScanFilter?)
|
||||
fun stopScan()
|
||||
fun isScanning(): Boolean
|
||||
fun connect(deviceId: String)
|
||||
fun connect(deviceId: String, autoConnect: Boolean?)
|
||||
fun disconnect(deviceId: String)
|
||||
fun setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Long, callback: (Result<Unit>) -> Unit)
|
||||
fun discoverServices(deviceId: String, withDescriptors: Boolean, callback: (Result<List<UniversalBleService>>) -> Unit)
|
||||
@@ -686,8 +686,9 @@ interface UniversalBlePlatformChannel {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val deviceIdArg = args[0] as String
|
||||
val autoConnectArg = args[1] as Boolean?
|
||||
val wrapped: List<Any?> = try {
|
||||
api.connect(deviceIdArg)
|
||||
api.connect(deviceIdArg, autoConnectArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
|
||||
@@ -61,6 +61,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
private val subscriptionResultFutureList = mutableListOf<SubscriptionResultFuture>()
|
||||
private val pairResultFutures = mutableMapOf<String, (Result<Boolean>) -> Unit>()
|
||||
private val rssiResultFutureList = mutableListOf<RssiResultFuture>()
|
||||
private val autoConnectDevices = mutableSetOf<String>()
|
||||
|
||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
UniversalBlePlatformChannel.setUp(flutterPluginBinding.binaryMessenger, this)
|
||||
@@ -213,7 +214,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
return safeScanner.isScanning()
|
||||
}
|
||||
|
||||
override fun connect(deviceId: String) {
|
||||
override fun connect(deviceId: String, autoConnect: Boolean?) {
|
||||
// If already connected, send connected message,
|
||||
// if connecting, do nothing
|
||||
deviceId.findGatt()?.let {
|
||||
@@ -232,24 +233,31 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val shouldAutoConnect = autoConnect ?: false
|
||||
if (shouldAutoConnect) {
|
||||
autoConnectDevices.add(deviceId)
|
||||
} else {
|
||||
autoConnectDevices.remove(deviceId)
|
||||
}
|
||||
val remoteDevice = bluetoothManager.adapter.getRemoteDevice(deviceId)
|
||||
val gatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
remoteDevice.connectGatt(
|
||||
context,
|
||||
false,
|
||||
shouldAutoConnect,
|
||||
this,
|
||||
BluetoothDevice.TRANSPORT_LE
|
||||
)
|
||||
} else {
|
||||
remoteDevice.connectGatt(context, false, this)
|
||||
remoteDevice.connectGatt(context, shouldAutoConnect, this)
|
||||
}
|
||||
gatt.saveCacheIfNeeded()
|
||||
}
|
||||
|
||||
override fun disconnect(deviceId: String) {
|
||||
autoConnectDevices.remove(deviceId)
|
||||
val gatt = deviceId.findGatt()
|
||||
if (gatt == null) {
|
||||
cleanUpConnection(deviceId)
|
||||
mainThreadHandler?.post {
|
||||
callbackChannel?.onConnectionChanged(deviceId, false, null) {}
|
||||
}
|
||||
@@ -955,15 +963,13 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanConnection(gatt: BluetoothGatt) {
|
||||
gatt.removeCache()
|
||||
gatt.disconnect()
|
||||
private fun cleanUpConnection(deviceId: String) {
|
||||
val deviceDisconnectedError: FlutterError = createFlutterError(
|
||||
UniversalBleErrorCode.DEVICE_DISCONNECTED,
|
||||
"Device Disconnected",
|
||||
)
|
||||
readResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
if (it.deviceId == deviceId) {
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
@@ -971,7 +977,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
writeResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
if (it.deviceId == deviceId) {
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
@@ -979,7 +985,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
subscriptionResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
if (it.deviceId == deviceId) {
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
@@ -987,7 +993,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
mtuResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
if (it.deviceId == deviceId) {
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
@@ -995,7 +1001,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
discoverServicesFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
if (it.deviceId == deviceId) {
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
@@ -1003,7 +1009,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
rssiResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
if (it.deviceId == deviceId) {
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
@@ -1012,6 +1018,12 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanConnection(gatt: BluetoothGatt) {
|
||||
gatt.removeCache()
|
||||
gatt.disconnect()
|
||||
cleanUpConnection(gatt.device.address)
|
||||
}
|
||||
|
||||
private fun onBondStateUpdate(deviceId: String, bonded: Boolean, error: String? = null) {
|
||||
val future = pairResultFutures.remove(deviceId)
|
||||
future?.let { it(Result.success(bonded)) }
|
||||
@@ -1134,14 +1146,27 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
) {}
|
||||
}
|
||||
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
|
||||
cleanConnection(gatt)
|
||||
val deviceId = gatt.device.address
|
||||
val shouldAutoConnect = autoConnectDevices.contains(deviceId)
|
||||
|
||||
// Always clean up internal state (futures, etc.)
|
||||
cleanUpConnection(deviceId)
|
||||
|
||||
// Send connection changed callback
|
||||
mainThreadHandler?.post {
|
||||
callbackChannel?.onConnectionChanged(
|
||||
gatt.device.address, false, status.parseHciErrorCode()
|
||||
deviceId, false, status.parseHciErrorCode()
|
||||
) {}
|
||||
}
|
||||
UniversalBleLogger.logDebug("Closing gatt for ${gatt.device.name}")
|
||||
gatt.close()
|
||||
|
||||
if (!shouldAutoConnect) {
|
||||
// Only close GATT resources when autoConnect is disabled
|
||||
gatt.removeCache()
|
||||
gatt.disconnect()
|
||||
UniversalBleLogger.logDebug("Closing gatt for ${gatt.device.name}")
|
||||
gatt.close()
|
||||
}
|
||||
// When autoConnect is enabled, keep GATT open for Android to reconnect
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user