Flutter V1 vs V2 Embedding, deprecated Android APIs and Colliding Kotlin Versions
Oct 30, 2021
To recap my sound null safety blog post: when you have forty package dependencies and you must move to sound null safety due to transitive dependencies you might have to convert a couple of plugins which lag behind on your own. Converting a codebase and a few plugins is a sizable work. However there are some more points in this module and technology stack which you have to keep an eye out. Most of these are related to the herd of plugins you depend on, and I realized with that many packages I am basically a developer shepherd watching over my stock. Are there any sheeps sick? Are all of them doing well? Are any of them dragging their feet?
I’ve read blog posts which warned against depending on too many plugins arguing that usually you only use fractions of the feature offerings and you could as well develop code on your own or borrow the needed pieces. But as soon as you borrow code you lose the advantage of a community. When you depend on a package a whole community is using it, finding issues and bugs, and contributing and fixing it. If you tear out some code you won’t have that power of the community any more and the code could become stale versus a more actively maintained one within a package. Of course by the statistical law of big numbers with many plugins there will be a few which lag behind. But overall I’m a huge fan of not reinventing the wheel and relying on packages heavily anyway.
An exception for borrowing code could be if it is purely in Dart land (so you don’t have to fiddle with native Android or iOS code) and you have a decent amount of customization and added features to it. Even in that case I’d constantly try to work towards contributing back to the original code so one day I can rely on a dependency again. For example I still hope that in case of the Fab Circular Menu the debugging of a significant issue and my solution to it will be mreged one day. Unfortunately in case of Strava and the TCX module I had way too much change in the API to support in-memory files so I don’t have a PR yet to contribute back.
So back the possible issues arising beyond sound null safety tasks:
- Plugins which still implement the Flutter V1 embedding API only.
- Plugins which use deprecated Android APIs.
- Kotlin version collision between dependencies.
Let’s look at those one-by-one.
Flutter V1 API vs V2 API
When you write a Flutter package there’s a well defined way to interface with the rest of the Flutter technology stack and that’s basically the Flutter embedding API. The V2 embedding API was introduced a long time ago with Flutter 1.12 and although the V1 API is still supported but it’s in a deprecated state and who knows when it will be unsupported. At 2020 Q2 only 26% of plugins were using V1 and the ecosystem stopped letting in V1 packages since then. For a good while I was dealing with a mixed set of V1 and V2 embeddings among my forty dependencies. There were reports that the initialization of any V1 plugins before V2 plugins could cause problems. I saw the related code inside the Flutter SDK. The scaffolding didn’t pay attention to which version a plugin is and it was also lacking any exception handling, so if any plugin creps itself the initialization sequence is interrupted and the application probably crashes upon startup.
Take a look at this proposed patch within a Flutter issue. I started to use that patch over the Flutter SDK to make sure that the generated scaffolding orders the V1 plugin initializations after the V2 ones. I had to stash that patch every time before I upgraded my Flutter SDK, then unstash it and recompile the SDK. This worked all the way until Flutter 2.5 came out at which point the related code area was refactored so much that the patch was not applicable any more. Since I kept constantly upgrading my plugins at that point only two of them used V1 embedding.
One of them was the bluetooth_enable plugin, and fortunately I found a fork of Alystrasz with a PR already upgraded to V2 embedding. Now there is a migration guide however the hard part of the work is up to you and not necessarily intuitive. I felt like little bit in the dark, but I finally upgraded the File and Screenshot Share Widget and it was quite a ride, needed to dig deep like this StackOverflow issue. Unfortunately I accidentally merged in a screenshot feature deletion so I scrambled to push another PR which brought the screenshot back. I felt awful, but provided a quick recovery hopefully redeeming myself. The plugin maintainer released the refreshed version so I could take out one reliance on a custom fork from my codebase and I’m back relying on the pub.dev package. Speaking about plugins dragging their feet the bluetooth enable plugin is another story: even though someone else already did the work the plugin maintainer still haven’t merged the PR.
Plugins which use deprecated Android APIs
I have about half a dozen of such plugins. Issues can be really nagging if they affect any permissions. The permission system got stricter the last 2-3 major Android versions. In my case this involves file saving, file import and bluetooth permissions. If anything gets out of alignment users may not be able to use my application and I’d get bad reviews. Right now I keep deferring this to deal with them since I just cannot carry all of them on my back. I hope that their respective maintainers will keep updating them. I purposefully haven’t updated the permission checker plugin for example. I already contributed to more than half a dozen plugins along my journey.
Kotlin version collision between dependencies
Fortunately this avoided me so far, however it could happen if your kotlin version or any of the plugin’s kotlin versions are too far apart. See this, this, or this Stackoverflow issue. Kotlin is a first class citizen Android language and it goes through a pretty good pace of evolution. ALong that way there can be some colliding changes, I won’t go into more details here.
These were a few areas to watch out for with any Flutter project which is bigger than a Hello World. Essentially time will solve most of these issues because V1 embedding will EOL (End of Life) at some point and the various deprecated Android APIs as well. Let’s hope the best that the community and the plugin maintainers will keep the momentum forward.