From 410e232b674b3d02fe7ee8b4003deb3e956fdfd9 Mon Sep 17 00:00:00 2001 From: Swanav Swaroop Date: Sat, 17 Jul 2021 02:21:42 +0530 Subject: [PATCH 1/5] Handle some common descriptors Handles common descriptors and the different type of values they will exchange. --- ios/Classes/FlutterBluePlugin.m | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/ios/Classes/FlutterBluePlugin.m b/ios/Classes/FlutterBluePlugin.m index 65a73b6d..636d710d 100644 --- a/ios/Classes/FlutterBluePlugin.m +++ b/ios/Classes/FlutterBluePlugin.m @@ -506,8 +506,29 @@ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDes } ProtosReadDescriptorResponse *result = [[ProtosReadDescriptorResponse alloc] init]; [result setRequest:q]; - int value = [descriptor.value intValue]; - [result setValue:[NSData dataWithBytes:&value length:sizeof(value)]]; + // Descriptors returning NSNumber (UInt16) + if ([descriptor.UUID.UUIDString isEqualToString: CBUUIDCharacteristicExtendedPropertiesString] || + [descriptor.UUID.UUIDString isEqualToString: CBUUIDClientCharacteristicConfigurationString] || + [descriptor.UUID.UUIDString isEqualToString: CBUUIDServerCharacteristicConfigurationString] ) + { + int value = [descriptor.value unsignedShortValue]; + [result setValue:[NSData dataWithBytes:&value length:sizeof(value)]]; + } + + // Descriptors returning NSString + else if ([descriptor.UUID.UUIDString isEqualToString: CBUUIDCharacteristicUserDescriptionString]) + { + NSData *value = [descriptor.value dataUsingEncoding: NSUTF8StringEncoding]; + [result setValue: value]; + } + + // Descriptors returning NSData + else if ([descriptor.UUID.UUIDString isEqualToString: CBUUIDCharacteristicFormatString] || + [descriptor.UUID.UUIDString isEqualToString: CBUUIDCharacteristicAggregateFormatString]) + { + [result setValue:descriptor.value]; + } + [_channel invokeMethod:@"ReadDescriptorResponse" arguments:[self toFlutterData:result]]; // If descriptor is CCCD, send a SetNotificationResponse in case anything is awaiting From 425c35b56362c0b49c919e016ab74acaa232324f Mon Sep 17 00:00:00 2001 From: Swanav Date: Thu, 14 Oct 2021 01:41:40 +0530 Subject: [PATCH 2/5] Updated proguard rules for release build --- android/build.gradle | 5 +++++ android/proguard-rules.pro | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 android/proguard-rules.pro diff --git a/android/build.gradle b/android/build.gradle index 6a2ce0de..a4821fef 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -36,6 +36,11 @@ android { } } } + buildTypes { + release { + consumerProguardFiles 'proguard-rules.pro' + } + } } protobuf { diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro new file mode 100644 index 00000000..9bffb490 --- /dev/null +++ b/android/proguard-rules.pro @@ -0,0 +1,2 @@ +# Retain Flutter Blue protocol buffer files +-keep class com.pauldemarco.flutter_blue.** { *; } From 5177cf94b602254dc22e4a4222bc1ac9145588f5 Mon Sep 17 00:00:00 2001 From: Swanav Date: Wed, 20 Oct 2021 00:22:52 +0530 Subject: [PATCH 3/5] Correct implementation of BluetoothDevice.connect() method to allow user code to catch connection timeout --- lib/src/bluetooth_device.dart | 43 +++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/src/bluetooth_device.dart b/lib/src/bluetooth_device.dart index ca3bb9ba..67532ff6 100644 --- a/lib/src/bluetooth_device.dart +++ b/lib/src/bluetooth_device.dart @@ -26,22 +26,55 @@ class BluetoothDevice { ..remoteId = id.toString() ..androidAutoConnect = autoConnect; + Completer _completer = Completer(); + Timer? timer; if (timeout != null) { timer = Timer(timeout, () { disconnect(); - throw TimeoutException('Failed to connect in time.', timeout); + if (!_completer.isCompleted) { + _completer.completeError( + TimeoutException('Failed to connect in time.', timeout)); + } }); } await FlutterBlue.instance._channel .invokeMethod('connect', request.writeToBuffer()); - await state.firstWhere((s) => s == BluetoothDeviceState.connected); - - timer?.cancel(); + await state.firstWhere((_state) { + bool connected = _state == BluetoothDeviceState.connected; + if (connected) { + timer?.cancel(); + if (!_completer.isCompleted) { + _completer.complete(); + } + } + return connected; + }, orElse: () { + if (!_completer.isCompleted) { + timer?.cancel(); + disconnect(); + _completer.completeError( + TimeoutException('Failed to connect in time.', timeout)); + } + return BluetoothDeviceState.disconnected; + }).then((_state) { + timer?.cancel(); + if (_state == BluetoothDeviceState.connected) { + if (!_completer.isCompleted) { + _completer.complete(); + } + } + }).catchError((error) { + timer?.cancel(); + disconnect(); + if (!_completer.isCompleted) { + _completer.completeError(error); + } + }); - return; + return _completer.future; } /// Cancels connection to the Bluetooth Device From b037019fd840018459f74e2ae69f49075c518145 Mon Sep 17 00:00:00 2001 From: Swanav Date: Wed, 20 Oct 2021 00:27:06 +0530 Subject: [PATCH 4/5] Updates to the Flutter SDK needed these changes --- example/lib/main.dart | 2 +- example/lib/widgets.dart | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index e4a55a1a..31bba3c2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -54,7 +54,7 @@ class BluetoothOffScreen extends StatelessWidget { 'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.', style: Theme.of(context) .primaryTextTheme - .subhead + .subtitle1 ?.copyWith(color: Colors.white), ), ], diff --git a/example/lib/widgets.dart b/example/lib/widgets.dart index aefdf262..23ae5949 100644 --- a/example/lib/widgets.dart +++ b/example/lib/widgets.dart @@ -135,7 +135,7 @@ class ServiceTile extends StatelessWidget { children: [ Text('Service'), Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}', - style: Theme.of(context).textTheme.body1?.copyWith( + style: Theme.of(context).textTheme.bodyText1?.copyWith( color: Theme.of(context).textTheme.caption?.color)) ], ), @@ -183,7 +183,7 @@ class CharacteristicTile extends StatelessWidget { Text('Characteristic'), Text( '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}', - style: Theme.of(context).textTheme.body1?.copyWith( + style: Theme.of(context).textTheme.bodyText1?.copyWith( color: Theme.of(context).textTheme.caption?.color)) ], ), @@ -245,7 +245,7 @@ class DescriptorTile extends StatelessWidget { Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}', style: Theme.of(context) .textTheme - .body1 + .bodyText1 ?.copyWith(color: Theme.of(context).textTheme.caption?.color)) ], ), @@ -289,11 +289,11 @@ class AdapterStateTile extends StatelessWidget { child: ListTile( title: Text( 'Bluetooth adapter is ${state.toString().substring(15)}', - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, ), trailing: Icon( Icons.error, - color: Theme.of(context).primaryTextTheme.subhead?.color, + color: Theme.of(context).primaryTextTheme.subtitle1?.color, ), ), ); From 9b994fc82a128a6abc20341172ef5df135227b62 Mon Sep 17 00:00:00 2001 From: Swanav Date: Wed, 20 Oct 2021 00:58:36 +0530 Subject: [PATCH 5/5] A small fix --- lib/src/bluetooth_device.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/bluetooth_device.dart b/lib/src/bluetooth_device.dart index 67532ff6..5424f77d 100644 --- a/lib/src/bluetooth_device.dart +++ b/lib/src/bluetooth_device.dart @@ -42,7 +42,7 @@ class BluetoothDevice { await FlutterBlue.instance._channel .invokeMethod('connect', request.writeToBuffer()); - await state.firstWhere((_state) { + state.firstWhere((_state) { bool connected = _state == BluetoothDeviceState.connected; if (connected) { timer?.cancel();