Long story short, I've been trying to fix some bugs in an app I've developed to communicate with a BLE power bank. On iOS it's working alright, but there's fatal exceptions on Android. Part of this is due to some misbehavior on the device's part - trying to figure a way around it.
Basically, the device is a bit finicky, and connecting to it goes something like:
BUT, all of these operations are part of a stream listener of the device state and the discovery methods and setNotify() methods are async.
More importantly, on the second time of trying to connect, there seems to be some duplicate firing. discoverServices() fires twice, setting the notification fires twice. It's as if there's a duplicate instance created and both try to work.
Notification error is:
PlatformException(set_notification_error, error when writing the descriptor, null) on setNotifyValue
Relevant github issue:
https://github.com/pauldemarco/flutter_blue/issues/295What I'm trying to solve:1. Workaround for when device connects immediately after connecting
This is obviously device-specific, but I've been bashing my head in looking for a solution. At first, I thought (okay, we'll try to go through discovery/setting notifications on the second connection attempt). The problem there is that, if someone else initiates the first connection (or in general it has failed the connection once before), the first try of the app succeeds and the connection is maintained. This means I can't be sure it happens every other connection attempt.
If I could somehow detect that is was the failed connection, I could hold off on performing the operations that cause the program to throw exceptions. I'll paste the code block for reference:
void connect(String deviceId) async {
var dev = devices[deviceId];
if (connectedDevices[deviceId] != null) return;
await dev.device.connect(autoConnect: false);
dev.connection = dev.device.state.listen((state) async {
dev.deviceState = state;
notifyListeners();
if (state == BluetoothDeviceState.disconnected) {
connectedDevices[dev.id] = null;
await dev.dispose();
notifyListeners();
}
if (state == BluetoothDeviceState.connected) {
dev.services = await dev.device.discoverServices();
for (BluetoothService service in dev.services) {
// set services based on uuid
}
for (BluetoothCharacteristic characteristic
in dev.deviceInfoService.characteristics) {
// set characteristics from services
}
for (BluetoothCharacteristic characteristic
in dev.notificationService.characteristics) {
switch (characteristic.uuid.toString()) {
case notificationServiceCharacteristic:
dev.notificationServiceCharacteristic = characteristic;
if (!dev.notificationServiceCharacteristic.isNotifying) {
await dev.notificationServiceCharacteristic
.setNotifyValue(true); // this is where the error is thrown. I've tried checking call count for the even number attempts to no avail
dev.valueChangedSubscription = dev
.notificationServiceCharacteristic.value
.listen((value) {
_onValuesChanged(dev, value);
notifyListeners();
});
connectedDevices[dev.id] = dev;
}
break;
case writeCharacteristic:
dev.writeCharacteristic = characteristic;
break;
default:
break;
}
}
notifyListeners(); //using scopedModel for handling state
await readServiceCharacteristics(dev);
}
});
}
2. Solving the case of duplicated calls
This seems a bit tougher, as there's currently work being done by the author himself to hopefully solve it:
https://github.com/pauldemarco/flutter_blue/issues/525However, I'm not just getting duplicated notifications - everything is being duplicated on occasion. Services discovered twice, notifications set twice, reading characteristics twice, etc. I thought the await would help, but it's not getting me any closer. This isn't a major issue, but after each successful reconnection the number of notifications per second per devices increases by 3. Given enough time, the app is crippled.
I've pinged the Flutter dev discord a few times, but it seems like there aren't a lot of developers working with bluetooth. Any suggestions would be greatly appreciated. Also feel free to contact me directly on discord at pandemic#0001
Thanks,
Brenden