Skip to content

Commit 49aa9d9

Browse files
spkerstenSander Kersten
andauthored
Support multiple services or characteristics with the same id (#776)
* Allow multiple services/characteristics of the same type on iOS * Allow multiple services/characteristics of the same type on Android * Update example to use new interface * Rename QualifiedCharacteristic to CharacteristicInstance to match Dart * Extend documentation * Update and extend tests * Address review comments * Update Kotlin tests --------- Co-authored-by: Sander Kersten <[email protected]>
1 parent 01f6dd0 commit 49aa9d9

File tree

57 files changed

+2462
-1426
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2462
-1426
lines changed

example/lib/main.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ void main() {
2424
logMessage: _bleLogger.addToLog,
2525
);
2626
final _serviceDiscoverer = BleDeviceInteractor(
27-
bleDiscoverServices: _ble.discoverServices,
28-
readCharacteristic: _ble.readCharacteristic,
29-
writeWithResponse: _ble.writeCharacteristicWithResponse,
30-
writeWithOutResponse: _ble.writeCharacteristicWithoutResponse,
31-
subscribeToCharacteristic: _ble.subscribeToCharacteristic,
27+
bleDiscoverServices: (deviceId) async {
28+
await _ble.discoverAllServices(deviceId);
29+
return _ble.getDiscoveredServices(deviceId);
30+
},
3231
logMessage: _bleLogger.addToLog,
3332
);
3433
runApp(

example/lib/src/ble/ble_device_interactor.dart

Lines changed: 3 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,16 @@ import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
44

55
class BleDeviceInteractor {
66
BleDeviceInteractor({
7-
required Future<List<DiscoveredService>> Function(String deviceId)
8-
bleDiscoverServices,
9-
required Future<List<int>> Function(QualifiedCharacteristic characteristic)
10-
readCharacteristic,
11-
required Future<void> Function(QualifiedCharacteristic characteristic,
12-
{required List<int> value})
13-
writeWithResponse,
14-
required Future<void> Function(QualifiedCharacteristic characteristic,
15-
{required List<int> value})
16-
writeWithOutResponse,
7+
required Future<List<Service>> Function(String deviceId) bleDiscoverServices,
178
required void Function(String message) logMessage,
18-
required Stream<List<int>> Function(QualifiedCharacteristic characteristic)
19-
subscribeToCharacteristic,
209
}) : _bleDiscoverServices = bleDiscoverServices,
21-
_readCharacteristic = readCharacteristic,
22-
_writeWithResponse = writeWithResponse,
23-
_writeWithoutResponse = writeWithOutResponse,
24-
_subScribeToCharacteristic = subscribeToCharacteristic,
2510
_logMessage = logMessage;
2611

27-
final Future<List<DiscoveredService>> Function(String deviceId)
28-
_bleDiscoverServices;
29-
30-
final Future<List<int>> Function(QualifiedCharacteristic characteristic)
31-
_readCharacteristic;
32-
33-
final Future<void> Function(QualifiedCharacteristic characteristic,
34-
{required List<int> value}) _writeWithResponse;
35-
36-
final Future<void> Function(QualifiedCharacteristic characteristic,
37-
{required List<int> value}) _writeWithoutResponse;
38-
39-
final Stream<List<int>> Function(QualifiedCharacteristic characteristic)
40-
_subScribeToCharacteristic;
12+
final Future<List<Service>> Function(String deviceId) _bleDiscoverServices;
4113

4214
final void Function(String message) _logMessage;
4315

44-
Future<List<DiscoveredService>> discoverServices(String deviceId) async {
16+
Future<List<Service>> discoverServices(String deviceId) async {
4517
try {
4618
_logMessage('Start discovering services for: $deviceId');
4719
final result = await _bleDiscoverServices(deviceId);
@@ -52,59 +24,4 @@ class BleDeviceInteractor {
5224
rethrow;
5325
}
5426
}
55-
56-
Future<List<int>> readCharacteristic(
57-
QualifiedCharacteristic characteristic) async {
58-
try {
59-
final result = await _readCharacteristic(characteristic);
60-
61-
_logMessage('Read ${characteristic.characteristicId}: value = $result');
62-
return result;
63-
} on Exception catch (e, s) {
64-
_logMessage(
65-
'Error occurred when reading ${characteristic.characteristicId} : $e',
66-
);
67-
// ignore: avoid_print
68-
print(s);
69-
rethrow;
70-
}
71-
}
72-
73-
Future<void> writeCharacteristicWithResponse(
74-
QualifiedCharacteristic characteristic, List<int> value) async {
75-
try {
76-
_logMessage(
77-
'Write with response value : $value to ${characteristic.characteristicId}');
78-
await _writeWithResponse(characteristic, value: value);
79-
} on Exception catch (e, s) {
80-
_logMessage(
81-
'Error occurred when writing ${characteristic.characteristicId} : $e',
82-
);
83-
// ignore: avoid_print
84-
print(s);
85-
rethrow;
86-
}
87-
}
88-
89-
Future<void> writeCharacteristicWithoutResponse(
90-
QualifiedCharacteristic characteristic, List<int> value) async {
91-
try {
92-
await _writeWithoutResponse(characteristic, value: value);
93-
_logMessage(
94-
'Write without response value: $value to ${characteristic.characteristicId}');
95-
} on Exception catch (e, s) {
96-
_logMessage(
97-
'Error occurred when writing ${characteristic.characteristicId} : $e',
98-
);
99-
// ignore: avoid_print
100-
print(s);
101-
rethrow;
102-
}
103-
}
104-
105-
Stream<List<int>> subScribeToCharacteristic(
106-
QualifiedCharacteristic characteristic) {
107-
_logMessage('Subscribing to: ${characteristic.characteristicId} ');
108-
return _subScribeToCharacteristic(characteristic);
109-
}
11027
}

example/lib/src/ui/device_detail/characteristic_interaction_dialog.dart

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,27 @@ class CharacteristicInteractionDialog extends StatelessWidget {
1010
required this.characteristic,
1111
Key? key,
1212
}) : super(key: key);
13-
final QualifiedCharacteristic characteristic;
13+
final Characteristic characteristic;
1414

1515
@override
1616
Widget build(BuildContext context) => Consumer<BleDeviceInteractor>(
17-
builder: (context, interactor, _) => _CharacteristicInteractionDialog(
18-
characteristic: characteristic,
19-
readCharacteristic: interactor.readCharacteristic,
20-
writeWithResponse: interactor.writeCharacteristicWithResponse,
21-
writeWithoutResponse: interactor.writeCharacteristicWithoutResponse,
22-
subscribeToCharacteristic: interactor.subScribeToCharacteristic,
23-
));
17+
builder: (context, interactor, _) => _CharacteristicInteractionDialog(characteristic: characteristic),
18+
);
2419
}
2520

2621
class _CharacteristicInteractionDialog extends StatefulWidget {
2722
const _CharacteristicInteractionDialog({
2823
required this.characteristic,
29-
required this.readCharacteristic,
30-
required this.writeWithResponse,
31-
required this.writeWithoutResponse,
32-
required this.subscribeToCharacteristic,
3324
Key? key,
3425
}) : super(key: key);
3526

36-
final QualifiedCharacteristic characteristic;
37-
final Future<List<int>> Function(QualifiedCharacteristic characteristic)
38-
readCharacteristic;
39-
final Future<void> Function(
40-
QualifiedCharacteristic characteristic, List<int> value)
41-
writeWithResponse;
42-
43-
final Stream<List<int>> Function(QualifiedCharacteristic characteristic)
44-
subscribeToCharacteristic;
45-
46-
final Future<void> Function(
47-
QualifiedCharacteristic characteristic, List<int> value)
48-
writeWithoutResponse;
27+
final Characteristic characteristic;
4928

5029
@override
51-
_CharacteristicInteractionDialogState createState() =>
52-
_CharacteristicInteractionDialogState();
30+
_CharacteristicInteractionDialogState createState() => _CharacteristicInteractionDialogState();
5331
}
5432

55-
class _CharacteristicInteractionDialogState
56-
extends State<_CharacteristicInteractionDialog> {
33+
class _CharacteristicInteractionDialogState extends State<_CharacteristicInteractionDialog> {
5734
late String readOutput;
5835
late String writeOutput;
5936
late String subscribeOutput;
@@ -71,13 +48,13 @@ class _CharacteristicInteractionDialogState
7148

7249
@override
7350
void dispose() {
51+
textEditingController.dispose();
7452
subscribeStream?.cancel();
7553
super.dispose();
7654
}
7755

7856
Future<void> subscribeCharacteristic() async {
79-
subscribeStream =
80-
widget.subscribeToCharacteristic(widget.characteristic).listen((event) {
57+
subscribeStream = widget.characteristic.subscribe().listen((event) {
8158
setState(() {
8259
subscribeOutput = event.toString();
8360
});
@@ -88,28 +65,23 @@ class _CharacteristicInteractionDialogState
8865
}
8966

9067
Future<void> readCharacteristic() async {
91-
final result = await widget.readCharacteristic(widget.characteristic);
68+
final result = await widget.characteristic.read();
9269
setState(() {
9370
readOutput = result.toString();
9471
});
9572
}
9673

97-
List<int> _parseInput() => textEditingController.text
98-
.split(',')
99-
.map(
100-
int.parse,
101-
)
102-
.toList();
74+
List<int> _parseInput() => textEditingController.text.split(',').map(int.parse).toList();
10375

10476
Future<void> writeCharacteristicWithResponse() async {
105-
await widget.writeWithResponse(widget.characteristic, _parseInput());
77+
await widget.characteristic.write(_parseInput());
10678
setState(() {
10779
writeOutput = 'Ok';
10880
});
10981
}
11082

11183
Future<void> writeCharacteristicWithoutResponse() async {
112-
await widget.writeWithoutResponse(widget.characteristic, _parseInput());
84+
await widget.characteristic.write(_parseInput(), withResponse: false);
11385
setState(() {
11486
writeOutput = 'Done';
11587
});
@@ -202,7 +174,7 @@ class _CharacteristicInteractionDialogState
202174
Padding(
203175
padding: const EdgeInsets.symmetric(vertical: 8.0),
204176
child: Text(
205-
widget.characteristic.characteristicId.toString(),
177+
widget.characteristic.id.toString(),
206178
),
207179
),
208180
divider,
@@ -217,8 +189,9 @@ class _CharacteristicInteractionDialogState
217189
child: Padding(
218190
padding: const EdgeInsets.only(top: 20.0),
219191
child: ElevatedButton(
220-
onPressed: () => Navigator.of(context).pop(),
221-
child: const Text('close')),
192+
onPressed: () => Navigator.of(context).pop(),
193+
child: const Text('close'),
194+
),
222195
),
223196
)
224197
],

0 commit comments

Comments
 (0)