dart_apitool updates

dart_apitool updates

Recently dart_apitool got 2 significant updates. Thanks to all the contributors that made that possible.

1. More robust preparation step

dart_apitool makes local copies of the packages it analyzes

When dart_apitool analyzes packages it has to do some preparation steps in order to make sure the analysis run doesn’t have any issues:

  1. it has to remove any analysis_options.yaml because this file can limit the scope of the analyzer.
    This is OK if you want to e.g. exclude files from linting but dart_apitool needs to see all of your files to create a complete model of your public API.
  2. it has to remove an example project as it needs to run pub get to get the dependencies prepared and up-to-date for a successful analysis run.
    Some packages have examples bundled with them that sometimes reach into packages via relative paths that live outside the package directory. Those paths are valid inside the package’s repository but are not valid outside of it. A dart_package bundles those examples which means they also live inside the downloaded package and might have invalid relative path dependencies.
    As dart_apitool is not interested in those examples it can just remove them from the package directory and run pub get to get the dependencies.

To not interfer with a local copy of the package (in the pub cache or on disk) dart_apitool makes a temporary copy of the package before manipulating it.

why this is complex and created an issue

This works really well. In the past there has been a special issue if a package was referenced on disk and contains relative path depdendencies. To solve that issue dart_apitool had a functionality to analyzse those path dependencies to determine the directory structure it needs to copy to the temporary directory making the relative path dependencies still work.

In the meantime dart (or better: pub) has a new feature: pubspec_overrides.yaml.
This is a separate file that can be used to override dependencies in a pubspec.yaml. As dart_apitool only looked into the pubspec.yaml it didn’t see those overrides and therefore didn’t know about the relative path dependencies that might be defined in there.
A potential solution to that would have been to also parse the pubspec_overrides.yaml file and take the dependencies defined in there into account.


Minimalistic Text will be unavaible in the Google Play Store

Minimalistic Text will be unavailable in the Google Play Store

This is a short notice to inform you that Minimalistic Text will be unavailable in the Google Play Store from September 1st, 2023.
The reason for this is that Google will increase the target API level restrictions for already existing apps. Till now those restrictions only applied to new apps or app updates but beginning of September they will also apply to already existing apps.
In practice this means that apps will only be visible by devices that still use the Android version that matches the target SDK version of the app.
For Minimalistic Text this means that it will only be visible by devices that still use Android 9 or older even though it technically would work on newer Android versions.
As the amount of changes that I would have to do in order to comply with the newer API level requirements and the fact that the core rendering part of Minimalistic Text uses Android APIs that change behavior when switching the target API level, I decided to not update the app anymore.

To still provide a way for users to download the app I will provide the APK file on my website.

I’m sorry for the inconvenience this causes.

Dart_apitool updates

Dart_apitool got an update!

The recent weeks I was working a bit on dart_apitool.
The major topics were:

Missing export detection

The way Dart allows to define the public API of a package can lead to situations in which the consumer of the API is able to receive an instance of a certain Type but can’t refer to that type directly (e.g. to define a variable or a parameter of that Type).

Let’s imagine a very simple dart package:

- lib
    - some_package.dart
    - src 
        - some_interface.dart
        - some_interface_impl.dart
        - used_type.dart


export 'src/some_interface.dart'
export 'src/some_interface_impl.dart'


#import 'used_type.dart'

abstract class SomeInterface {
    UsedType doSomethingAndReturnInstance();

Struggles with the Dart type system

Struggles with the Dart type system

How it began: dart_apitool bug fix

It all started with a bug fix in dart_apitool.
The bug was that dart_apitool detected a breaking change on any parameter type change. Most of the time this is correct but consider this change:

/// version 1
void someMethod(String someParameter);

/// version 2a
void someMethod(String? someParameter);

/// version 2b
void someMethod(Object someParameter);

Here the type of the parameter gets changed but in a non-breaking way.
Any already existing call to someMethod will work with version 2a and version 2b.
The reason for this is that widening the type makes the old type part of the supported type space for that parameter.
Of course this is only valid for types passed in (which is the case for this bug as it describes method parameters).

So the goal was clear: dart_apitool has to check if the old type is assignable to the new type to decide if that change is a breaking change or not.


Software developmentFlutter

dart_apitool goes bmw-tech

dart_apitool goes bmw-tech

Today I have some exciting news to share!

Dart_apitool has been transferred to bmw-tech. The repository as well as the package on pub.dev are now under control of the BMW open source organization.

“Why?” You may ask

There are two major reasons for that move:

1. The need arose at BMW

Dart_apitool has been born out of a need in the “My BMW” development organization. The need for a tool that automatically can check correct semantic versioning of packages to avoid creating a mess when modularizing the app.
Puzzled by the realization that no such tool existed I took this as a challenge and made the development of dart_apitool my evening pet project.

2. BMW is the only user that I’m aware of

Besides not getting much traction in the Flutter community dart_apitool is used internally at BMW and already got some contributions from BMW colleagues.

I’m not sure why there is a lack of community traction. I can imagine those reasons:


Software developmentFlutter

dart_apitool improvements

dart_apitool improvements

There has been some new development in dart_apitool.

I got some feedback from our internal “My BMW” app teams and from the Flutter community so dart_apitool has received some extensions, improvements and fixes the last months:


Software development

Warp terminal

Warp terminal

The Terminal app is the Software developers best friend. This is the most used tool followed by the IDE (ignoring the Browser of course).
As you can see in the blog posts I did I experiment(-ed, more on that later) with building my own Terminal application so that I can stuff in all the features that I want to have in the terminal I use.

Sometimes you are so used to the status quo that you are not able to imagine that the tool you use so frequently could be so much better. The same thing happened to me with Terminal apps. The core of every terminal application was basically the same. The way you enter commands, the way your input gets mirrored, the way the output of the command gets shown and so on.
There are a few options to tweak things and enrich the capabilities of this experience like oh-my-zsh or Oh My Posh to name a few.

But then came Warp.


Software development

Antlion ModMic Wireless

Antlion ModMic Wireless

This is just a small post about a small gadget I bought recently: The Antlion ModMic Wireless.

Headset issues

Headsets were always a bit problematic for me. Already “in the office” but even more so in a Home Office or hybrid setting.
This issue might be home-grown, but I really hate wired headsets. The cable is always in the way and regardless of the side the cable is at it always interferes with me operating the computer.
So I needed something wireless.
I already have a couple of Bluetooth headsets, but they are not good for voice communication. They have to switch to “HFS/HFP” mode to use the microphone which totally kills the audio quality. Another issue with them is that the microphone quality is lacking, so this was not a good option.
For some time I used my Gaming headset for Teams meetings at the home office. This worked quite good, although the sound quality is nothing I want to listen to music with.
As the Gaming headset started to break I decided to look for another solution.

Gaming Headsets

The big advantage of that Gaming Headset is that it is wireless using a proprietary 2.4GHz protocol. This means that the headset is not dependent on Bluetooth and the audio quality is good even with activated microphone.
Looking at the current market for Gaming Headsets revealed a couple of good options that could replace my old one but still not being a good option for listening to music.
Gaming headsets - especially the good ones - also tend to show off that they are gaming headsets. Not that this would be a problem, but I don’t want flashing LEDs on my headset in a Teams video call 😁 (I know that this can be turned off for most of them, but you get the point).
There are some Bluetooth headsets out there that get quite good microphone reviews, but they lack in music playback quality.



Some dart_apitool updates

Some dart_apitool updates

In the recent months I have been working on some updates for dart_apitool.
The main changes I did were:

Removal of using model files

After thinking more about the use cases for the option to store a public API model to a file in order to use it later to diff against a new version I came to the conclusion that this won’t be used in practice very often.
The amount of maintenance needed to support loading older versions of models and support comparing that with a new model based on the current code base was too high for that feature not being used by anyone.
So I decided to just remove that feature completely.


Generalization of “classes”

Dart_apitool already supported the analysis of real “classes”. As interfaces in Dart are just abstract classes they were supported automatically.
But there are other concepts in Dart, that are quite similar to classes but not exactly the same. Things like Mixins for example.
So I decided to change the API used in dart_apitool to handle all those entities as “interfaces”.

Required interface support

We had a problem with the sqflite package at work. It published an update to an internal package that broke our build. Using that as perfect feature request and integration test for dart_apitool I analyzed what exactly caused the issue.
Dart_apitool would not have been able to detect that breaking change. The reason for that is that it was not aware of the difference between “required” and “provided” interfaces.


Software developmentFlutter

Dart & semver hygiene

Dart & semver hygiene

What is semver?

The term semver means “semantic versioning” and is used to describe software releases.
It is defined here.

The essence of this rule-set is to couple the kind of (API) change with the version of the software. If you make a breaking change then you have to increase the major version and for non-breaking changes you have to increase the minor version (simplified).
This rule-set is the recommended way to version dart packages and all the mechanisms to resolve versions of dependencies rely on that.

What is the problem?

In general, I think semver works quite well, but sometimes it happens that a breaking change slips through.
This can have dramatic consequences.
If a package releases a new version and only increases the minor version or the patch version while still containing breaking changes then builds of dependent projects will fail without the developer specifying a new version.
This is because it is considered best practice (even a requirement) for packages to not depend on an exact version but on a compatible version range. This is done by assuming that any newer version that doesn’t increase the major version is backwards compatible.
But even if you don’t have a direct dependency on that package you might have a transitive dependency (e.g. if a package you depend on depends on that package) and you get your build broken as a result.

Is there something I can do about it?

At least soon™️.

We were facing such a transitive dependency build breakage and I wondered if there is an easy way to integrate a semver check into a CI pipeline and why package maintainers don’t check that automatically.
After some research I was not able to find a utility that could be used to do such a check, so I decided to create one myself.

Welcome dart_apitool


Software developmentFlutter