flutter-plugins
flutter-plugins copied to clipboard
[Pedometer 4.0.1] stepCountStream can hang on iOS
Device / Emulator and OS
- Device: iPhone 13 Pro
- OS: iOS 16.4 or 17.0
Describe the bug
When my app starts I need to query for the current pedometer reading. The only way to do this with the plugin API is grab the first value off the stream:
final stepCount = await Pedometer.stepCountStream.first
Normally this works fine but I've found that this call never returns in some edge cases. Leaving my app to hang on start.
To Reproduce
- Reboot the phone
- Do not move it, leave it docked or laying on your desk
- Call
await Pedometer.stepCountStream.first
-- app hangs - pick up phone and walk around
- API call returns a result and from now on you get instant results from this API call
Expected behavior
- The api should always return a response
Actual behavior
stepCountStream
does not return any response until the device starts moving
Flutter doctor
n/a
Additional information
I stepped into the swift native code and determined that this is expected/undocumented behavior of CMPedometer after a reboot.
...
pedometer.startUpdates...
...
does not return on the callback but if I replace that code with this
pedometer.queryPedometerData(from: dateOfLastReboot, to: Date()) { pedometerData, error in
guard let pedometerData = pedometerData, error == nil else { return }
DispatchQueue.main.async {
self.handleEvent(count: pedometerData.numberOfSteps.intValue)
}
}
it works as you would expect. I get an immediate response on the callback regardless of reboot.
Workaround
For those interested, I added a timeout to the Dart Future to get around this for now. This throws an exception which can be handled in a try/catch:
try {
final stepCount = await Pedometer.stepCountStream.first.timeout(const Duration(milliseconds: 100));
return Result.value(stepCount.steps);
} catch (e) {
return Result.error(e);
}
P.S. - after seeing how this timeout works on anything that returns a Dart Future I think it's quite elegant already. Maybe I should be doing this for any API calls? I'll leave this bug report here but my solution works for my purposes.