The Joy of Production Only Bugs

Nov 26, 2020

In my previous Track My Indoor Workoutblog post I laid out plans to fix a Strava upload issue, UX changes, and mentioned iOS support. I’d like to follow-up on these and report my progress.

Regarding UX I made the activity details view and the activity list view style similar to the activity measurement screen: using 7-segment and 14-segment fonts, larger texts and similar iconography. I got engaged with two of my users and I’d like to thank them for their inputs and suggestions: shout out to David Veneski and Todd Fine.

I also introduced three features which can decrease the number of clicks required from app start to Strava upload to only one. All of these features are configurable on the preferences screen and can be turned on or off as desired:

  1. Auto scan (on by default): after app startup a scan for exercise equipment will start immediately.
  2. Auto start workout (off by default): if enabled and there’s only one exercise equipment as the result of the scan then the app immediately connects to it and kicks off the activity measurement. Another auto-start criteria is if there would be multiple equipment in the scan results, but one of them would be the previously used equipment then the app will pick that and also start the measurement. In fact when the app sees that familiar equipment - while the scan is still in progress - it’ll interrupt the scan and move to the workout.
  3. Auto Strava upload (off by default): if enabled and the user already authenticated with Strava and there’s data connection available then the app will immediately kick off the upload procedure after the workout end is signalled by the user (pressing the stop button).

If all of these three features are turned on then once the app is started ideally the user only has to click once to stop the workout and actions will happen seamlessly and smoothly.

I had to solve the Strava upload issue reported by my users. This turned out to be tricky. First I suspected that the old Android version (Android 5 on an ASUS Zenfone) could be a culprit or it might be that the Zenfone is running on x86 architecture (Intel Atom CPU) as opposed to the industry dominant ARM architecture? This hunch proved to be wrong when another user experienced the same issue with a Pixel 4a running Android 11.

I tried to reproduce the problem on my OnePlus 6 (Android 10), on a Moto G6 (Android 9) bought for projects and on a Samsung Galaxy S4 (Android 9) without success. Then it accidentally struck me: I was trying to reproduce the issue with debug versions on all of these devices, and finally it turned out that it’s a release version only issue. That’s harder to track down especially in case of flutter because you won’t get as good crash call stack symbolications.

The Play Store console displayed two warnings about missing debug symbols:

  • for Kotlin ("This App Bundle contains Java/Kotlin code, which might be obfuscated. We recommend you upload a deobfuscation file to make your crashes and ANRs easier to analyze and debug")
  • for native code ("App Bundle contains native code, and you’ve not uploaded debug symbols").

The Flutter app’s Android port has Kotlin shim code, hence the Kotlin warning and the whole Dart/Flutter technology stack resides in native land. Even to cure these two warnings required jumping several hoops and fiddling around with the build pipeline. Then I peeked at the 100 miles per hour velocity log flood in LogCat and tried to catch anything which stood out.

  • I thought it might be an issue with the information passing during the OAuth process and applied a workaround for this network security issue. However that affected only specific versions in the past, but I tried to throw everything at my problem to make it go away. Later I removed this workaround because it is not needed.
  • I also applied a workaround for CLEARTEXT_NOT_PERMITTED issue but just like the previous one this wasn’t the cure, so later I removed it as well.
  • There was a legitimate exception about "Bad state: Stream has already been listened to." at the code which was listening on the returning code from the OAuth process. I tried to fix this more subtle way but finally I resorted to a simple ‘.boradcas();’ call which would allow multiple listeners. The Strava upload still didn’t work with release builds.
  • There was an SQLite constraint violation exception on the call stack "code 2067 SQLITE_CONSTRAINT_UNIQUE" during an insert operation, but after lengthy tracking I concluded that it’s not by my application but rather some surrounding processes.
  • There was also a "SocketException: Failed host lookup: ‘www.strava.com’ (OS Error: No address associated with hostname, errno = 7)" and I realized that since I spinned out my own copy of strava_flutter I would not inherit the INTERNET permission transitively from its manifest. So I added <uses-permission android:name="android.permission.INTERNET" /> to my AndroidManifest.xml.

In conclusion the .broadcast() call and the internet permissions indication together cured the issue, but this was a lengthy road. To make things worse during one of my changes I upgraded some package versions. Nothing serious, just minor or step version bumps. One of these innocently upgraded the flutter_blue plugin from 0.7.2 to 0.7.3 version. That’s not even a minor version change, right? Well this broke the Bluetooth support - also only in release version. Right now I reverted to and pinned flutter_blue to 0.7.2 to fix this. I’d need to be very careful with the upcoming releases.

I’ll address iOS and more equipment support plans in my next blog post.

Comments loading...