flutter_reactive_ble
flutter_reactive_ble copied to clipboard
Error While Trying To Subscribe To Characteristic On iOS.
Describe the bug I'm trying to subscribe to a feature, but an error is raised. Which is confusing, because days ago it was working correctly, without any problems.
To Reproduce Steps to reproduce the behavior:
- Connect to one / many devices using
connectTo()
- Read/Write - ok
- Subscribe - error
Smartphone / tablet
- Device: iPhone XS
- OS: iOS 15.0
- Package version: 4.0.1
Additional context
In the version 5.0.0
of package, error persist.
In example app when click the Subscribe button this occurs in the log:
![Captura de Tela 2021-10-13 às 11 08 36 AM](https://user-images.githubusercontent.com/26651347/137149797-65ada5f1-7b5f-4610-9872-e82f324ee5f8.png)
@remonh87 had the same problem with the example app? Need help for this.
@yuriboeira11tx does your characteristic support subscribing and also we reverted some change in 5.0.2 which can be worth to try out.
So, I decided to test this version yesterday via the example application. Unfortunately the error persists! On Android it's running beautifully, the problem is on iOS. It gives the same error when it gets to the subscribeToCharacteristic()
line. I think it probably has to do with some system update as I'm testing both my app and the sample app and it's not working on iOS 15.0. I hope they can identify the problem. Does this error happen in your project?
And yes, my feature has subscription support and I can prove why it works on Android (version 11).
@yuriboeira11tx I encounter the same error on iOS and able to reproduce it with the Example app. I'm not sure if it's the same cause as the issue described in this ticket, but at least in my case, it looks like the device does not correctly specify the Client Characteristic Configuration Descriptor for custom notifiable characteristics. I found other issues described similar error condition:
- https://github.com/PhilipsHue/flutter_reactive_ble/issues/188
- https://github.com/xabre/xamarin-bluetooth-le/issues/191
- https://github.com/PhilipsHue/flutter_reactive_ble/issues/309
- https://github.com/randdusing/cordova-plugin-bluetoothle/issues/405
Even with the error, the subscription to custom characteristics should still work and the client should receive notification data. To test this, modify the plugin's Central.swift
in the PeripheralDelegate:onCharacteristicNotificationStateUpdate
to always return nil
for error as follow:
onCharacteristicNotificationStateUpdate: papply(weak: self) { central, characteristic, error in
central.characteristicNotifyRegistry.updateTask(
key: QualifiedCharacteristic(characteristic),
action: { $0.complete(error: nil) } // <-- don't forward error for testing only
)
}
Compile and run the Example app:
- Select a notifiable characteristic
- Select
Subscribe
- Select
Read
- The characteristic data should be displayed for both
Read
andSubscribe
@remonh87 This PR, https://github.com/PhilipsHue/flutter_reactive_ble/pull/193, seems to fix similar issue on Android. Do we need to have a similar PR for iOS? This is my naive implementation,
onCharacteristicNotificationStateUpdate: papply(weak: self) { central, characteristic, error in
let err: Error? = {
guard let nserror = error as NSError?
else { return error }
if (nserror.code == 10 && (characteristic.descriptors?.isEmpty ?? true) == true) { return nil }
return error
}()
central.characteristicNotifyRegistry.updateTask(
key: QualifiedCharacteristic(characteristic),
action: { $0.complete(error: err) }
)
}
Thanks for the collaboration, I will ask my colleague who developed the firmware to check if he implemented descriptors. I'll be back with updates on the case. But one factor that shouldn't go unnoticed is that before the 15.0 version of iOS, it worked perfectly and even faster than Android. But at the moment, iOS is kind of inactive in my project.
@werediver I noticed @k10dev did some interesting observations. Can you have a look at it?
@remonh87 @k10dev It's surprising that the subscription still works after an error is reported. If that's indeed acceptable to conditionally ignore that error, we should check not only the error code, but also the error domain, put the human readable error description in a comment and explain why that is needed.
@remonh87, @k10dev @werediver Hey guys. I come to let you know that the problem has been fixed. There is no problem with the library, it is working perfectly on both platforms. The important information is that, it is necessary that the firmware has descriptors in its characteristics. Otherwise this exception is thrown and feature subscription will not work on iOS. Thanks for the clarification and support!
I will leave this issue open and will add additional text to the error description. Good catch!!
@remonh87 @werediver We still would like to have a patch for backward compatibility to support devices in production that can't be updated with new firmware. We've made the fix in our firmware going forward.
There is another interesting observation. For characteristic with correct descriptors specified, but not have the BluetoothGattCharacteristic.PERMISSION_WRITE
added to the characteristic.properties
, we would receive this error instead Error Domain=CBATTErrorDomain Code=3 "Writing is not permitted."
. Similar to the other error 10
, the client would continue to receive the notification data. Perhaps the workaround should include a check for this as well
onCharacteristicNotificationStateUpdate: papply(weak: self) { central, characteristic, error in
let err: Error? = {
guard let nserror = error as NSError?
else { return error }
if (nserror.domain == "CBATTErrorDomain"
&& (nserror.code == 3
|| nserror.code == 10 && (characteristic.descriptors?.isEmpty ?? true) == true
)) {
return nil
}
return error
}()
central.characteristicNotifyRegistry.updateTask(
key: QualifiedCharacteristic(characteristic),
action: { $0.complete(error: err) }
)
}
I did encounter an exception in the Flutter code in the callback on receiving this error
Error Domain=CBATTErrorDomain Code=1 "The handle is invalid." UserInfo={NSLocalizedDescription=The handle is invalid.}
onCharacteristicValueUpdate: papply(weak: self) { central, characteristic, error in
onCharacteristicValueUpdate(central, QualifiedCharacteristic(characteristic), characteristic.value, error)
}
Stacktrace:
Runner[1790:899573] flutter: Exception: GenericFailure<CharacteristicValueUpdateError>(code: CharacteristicValueUpdateError.unknown, message: "Error Domain=CBATTErrorDomain Code=1 "The handle is invalid." UserInfo={NSLocalizedDescription=The handle is invalid.}")
Runner[1790:899573] flutter: #0 Result.dematerialize.<anonymous closure> (package:reactive_ble_platform_interface/src/model/result.dart:22:13)
#1 Result.iif (package:reactive_ble_platform_interface/src/model/result.dart:34:21)
#2 Result.dematerialize (package:reactive_ble_platform_interface/src/model/result.dart:15:28)
#3 ConnectedDeviceOperationImpl.readCharacteristic.<anonymous closure> (package:flutter_reactive_ble/src/connected_device_operation.dart:47:40)
#4 _MapStream._handleData (dart:async/stream_pipe.dart:213:31)
#5 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
#6 _rootRunUnary (dart:async/zone.dart:1436:47)
#7 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#8 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#10 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#11 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
#12 _WhereStream._handleData (dart:async/stream_pipe.dart:195:12)
#13 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
#14 _rootRunUnary (dart:async/zone.dart:1436:47)
#15 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#16 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#17 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#18 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#19 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
#20 _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
#21 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
#22 _rootRunUnary (dart:async/zone.dart:1436:47)
#23 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#24 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#25 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#26 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#27 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
#28 _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
#29 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
#30 _rootRunUnary (dart:async/zone.dart:1436:47)
#31 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#32 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#33 CastStreamSubscription._onData (dart:_internal/async_cast.dart:85:11)
#34 _rootRunUnary (dart:async/zone.dart:1436:47)
#35 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#36 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#37 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#38 _DelayedData.perform (dart:async/stream_impl.dart:591:14)
#39 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:706:11)
#40 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:663:7)
#41 _rootRun (dart:async/zone.dart:1420:47)
#42 _CustomZone.run (dart:async/zone.dart:1328:19)
#43 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#44 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#45 _rootRun (dart:async/zone.dart:1428:13)
#46 _CustomZone.run (dart:async/zone.dart:1328:19)
#47 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#48 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#49 _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
#50 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
@k10dev Are you absolutely sure your app doesn't attempt to write to that characteristic when you're getting "Writing is not permitted"?
@werediver I actually used the Example app, and as soon as I select the Subscribe
button, it would return the Writing is not permitted
error.
Hello, @werediver @k10dev @remonh87 I am also facing the same issue with this plugin. I am using the example provided in your repository and my app is working fine with Android phones.
Getting below error while calling subscribeToCharacteristic
method.
flutter: Error unsubscribing from notifications: PlatformException(CBATTErrorDomain:10, The attribute could not be found., {NSLocalizedDescription: The attribute could not be found.}, null)
flutter: Error unsubscribing from notifications: PlatformException(CBATTErrorDomain:10, The attribute could not be found., {NSLocalizedDescription: The attribute could not be found.}, null)
flutter: Error unsubscribing from notifications: PlatformException(CBATTErrorDomain:10, The attribute could not be found., {NSLocalizedDescription: The attribute could not be found.}, null)
flutter: Error unsubscribing from notifications: PlatformException(CBATTErrorDomain:10, The attribute could not be found., {NSLocalizedDescription: The attribute could not be found.}, null)
flutter: Error unsubscribing from notifications: PlatformException(CBATTErrorDomain:10, The attribute could not be found., {NSLocalizedDescription: The attribute could not be found.}, null)
flutter: Error unsubscribing from notifications: PlatformException(CBATTErrorDomain:10, The attribute could not be found., {NSLocalizedDescription: The attribute could not be found.}, null)
Note: There is no issue with my firmware as I am able to get the data from characteristics using BLE Scanner App.
Hello, this morning i did some testing and found that there is now an exception throwing when i disconnect from my device.
flutter: Disconnecting to device: 5DD0594D-2562-AC72-EE0F-B066FE45C95C
flutter: Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.Central.(unknown context at $10338f0e4).Failure:1, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $10338f0e4).Failure error 1.), {}, null)
Hello, this morning I did some testing and found that there is now an exception throwing when i disconnect from my device.
flutter: Disconnecting to device: 5DD0594D-2562-AC72-EE0F-B066FE45C95C flutter: Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.Central.(unknown context at $10338f0e4).Failure:1, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $10338f0e4).Failure error 1.), {}, null)
@yuriboeira11tx I have also applied the same workaround which @k10dev mentioned in his comment and now facing the same issue as you.
@remonh87 @werediver
@dhaval-k-simformsolutions @yuriboeira11tx Are you using the Example
app for testing? I only able to recreate the issue with the Example
app when I press the Subscribe
button multiple times. The exception is thrown in the Central:resolve
function when there isn't an active peripheral for a given uuid,
private func resolve(connected peripheralID: PeripheralID) throws -> CBPeripheral {
guard let peripheral = activePeripherals[peripheralID]
else { throw Failure.peripheralIsUnknown(peripheralID) } // <-- Error
guard peripheral.state == .connected
else { throw Failure.peripheralIsNotConnected(peripheralID) }
return peripheral
}
This error is most likely caused by the code in the Example
app by disconnecting the peripheral multiple times and not in the plugin.
@k10dev Yes I am using the example app for the testing and I am getting the above exception while I perform the below steps in the example app.
- Connect to device
- Discover Services
- Subscribe under any characteristics and I am able to get the data
- Disconnect with device
- Discover services again(I got duplicate data this time for the service IDs - check this comment in issue #384 )
After connecting to the second time with the same device if I click on subscribe, Not get any data, and then if I click on the Disconnect in iOS getting the below exception:
688091db-1736-4179-b7ce-e42a724a6a68 Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.PluginError:7, The operation couldn’t be completed. (reactive_ble_mobile.PluginError error 7.), {}, null)
Note: Facing a similar type of issue while disconnecting with the device and reconnecting and then trying on subscribe but the exception is slide different. #384 is already open for the same.
I think this is related to the issue where we get the duplicate data for the service ids while we reconnect with the same device, maybe both are connected somewhere.
I had the same error. I was able to fix it by canceling the BLE Characteristic Streams first, adding a delay of a few hundred milliseconds then canceling the ConnectionStateUpdate stream.
example
await characteristicStream?.cancel(); await Future.delayed(const Duration(milliseconds: 300)); await deviceConnectionStateStream?.cancel();
https://github.com/PhilipsHue/flutter_reactive_ble/issues/586
@yuriboeira11tx
@remonh87
I am having almost the same error and I tried @saho-ventures solution but did not help
I am getting the following error when I:
- Connect to a device
- Subscribe to a characteristic
- Disconnect from the device
- Connect again to the device
- Discover services
The error I get is:
Error occured when discovering services: PlatformException(reactive_ble_mobile.Central.(unknown context at $10390b160).Failure:2, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $10390b160).Failure error 2.), {}, null) PlatformException
Do you have more informations about the failure code 2 ? I tried to reproduce this in the example app but could not.
Does Anybody found work around for the same as i am getting below exception.
PlatformException(reactive_ble_mobile.Central. (unknown context at $1047c6d94). Failure:5, The operation couldn't be completed. (reactive_ble_mobile Central (unknown context at $1047c6d94).Failure error 5.), {}, null)
I had the below error when I:
- connectToAdvertisingDevice
- subscribeToCharacteristic
flutter: PlatformException(reactive_ble_mobile.Central.(unknown context at $10269b160).Failure:5, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $10269b160).Failure error 5.), {}, null)
It turns out it was because my characteristic was not notifiable, I had to modify the firmware to make it notifiable
I still however, get this error:
flutter: Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.Central.(unknown context at $10269b160).Failure:5, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $10269b160).Failure error 5.), {}, null)
When I close the streams of
- connectToAdvertisingDevice
- subscribeToCharacteristic
But it doesn't seem to affect the functionality