This is Part 2 of the blog series in which I reflect on eleven years of work on Bandwidth Monitor. You can find Part 1 here, which goes into detail on how it started, or go to Part 3.
In this part, I’ll describe the development and maintenance work that went into the app over the years.
Version 1.0—1.5
After the release of version 1.0.0, I took the time to refine the app and incorporate user feedback.
App Store reviews have always been a crucial part of the app development process, but the feedback can sometimes be hard to process. I poured a lot of my time into making the app as best as I could, but there were bound to be edge cases and real-world environments it couldn’t handle. As a developer, I had to learn to separate myself from the product while still being proud of my own work.
The first major version had five minor versions which introduced quite a few base features of today’s app.
Overall, I introduced support for Today Widgets (the most requested feature), developed a full iPad variant, and allowed HTTPS traffic (with self-signed certificates).

Today Widget in 2018
The settings grew to include small but useful details, like switching between byte and bit display, or overriding the maximum upload/download values in case your router reported them incorrectly.
New iOS versions also meant adding support for dark mode with iOS 13, using SF Symbols to convey system-wide concepts to users, and changing the UI to keep up with trends across the system and the third-party ecosystem, like bottom sheet presentations.
Over time, the dependencies that the first version was built upon, like Realm, got replaced with hand-tailored solutions that made the app more efficient.
Of course, keeping the app maintained also meant continuous migration of Swift versions, first to version 4 and then finally to version 5. This is the major version the app has been running on until version 3.2, and only just recently did I finish the complete Swift 6 migration.
I had all these ideas of what features the app could include and which system functions it could hook into to make them possible. However, I quickly noticed that the crunch for the 1.0 release took a lot of my free time. I wanted to spend the time with other things for a while. Whenever I got the time and motivation to work on Bandwidth, I wanted to finish the changes by the end since I was never quite sure how long it would otherwise lie around. Getting into a half-developed feature after weeks was at times really hard.
Learning: Realistically estimate how much time you are able to regularly work on the project. Emphasis on regularly.
In June 2018, the app got featured in an article which drove a comparatively huge number of new users, and Bandwidth reached #90 in the App Store “Utilities” category.

Bandwidth at rank 90 in the “Utilities” category
Version 2.0
Version 2.0 was a complete rewrite of the app, all its internals as well as the user interface layer. It took from October 2019 to May 2021 — about 300 commits in 19 months — to finish: a major undertaking.
The rewrite also took quite a while because a lot happened in other areas of my life, including writing my master’s thesis and living through the global COVID pandemic — both of which caused their share of disruption.
This was once again one of the gaps I wished would have been shorter but life got in the way.
Learning: Working on the same type of project as your day job makes it harder to stay motivated, since you are tackling similar problems all day already.
In 2019, Apple introduced the SwiftUI framework for its platforms. It has come a long way since, and I was an adopter since day one, building first only a handful of views, and then later the entire app with it.
Also in 2019, the Combine framework was introduced. Professionally, I had been working on an AngularJS application the year before and had heavily gone into Observables. Combine’s equivalent is Publishers, and I was excited to see the concept of “values over time” coming to Apple platforms. I took this chance to rewrite the core dataflow across the app using publishers, thereby leveraging first-party framework support as best I could.
Feature-wise, this was the first time that the app could save multiple configurations as well. It let users quickly switch between configurations, for example, if they’re regularly looking at the data of different routers.
New networking core
Underneath, I migrated away from Alamofire (AFNetworking’s Swift successor) to a custom network client built on top of URLSession directly.
This allowed me to revisit other areas of the networking stack as well, and rethink in which ways the app was capable of helping the user. One of these was adding UPnP device discovery implemented via the Network framework. It is a bit heavier to use than what I was typically used to, but once it worked, it was super stable.
During 2021, the manufacturer of FRITZ!Boxes, AVM, put out the new firmware version 7.24 which changed the login system. By default, the routers are distributed with a password only. The devices support creating full user logins with username and password, but this is less often used. In a typical use case, the user is only asked for their password. This didn’t change from a user’s perspective.
For API clients, however, passing a username was now always required. The API exposed a call to find out which users were available to log in on the router, and the username-less authentication had a default username in the format “fritz1234”.
I found out about this change from my users, since my own router hadn’t received the update yet, and had to figure out why I suddenly got reports of errors during authentication. AVM created a helpful migration guide for the new flow, but it still took some time to adapt my data flow and views.
The new widget system
The switch to SwiftUI also meant that the Today widget had to be removed. This decision was controversial among my users as it removed one of the most used features. I did not make this decision lightly. However, the rewrite required extra work to keep supporting the old infrastructure. At the time, new homescreen widgets were the big new feature of iOS 14, and everyone was adopting them. Today Widgets were deprecated (and removed in a future iOS update), so the writing was on the wall already.
The main change was the runtime behavior: While Today Widgets were allowed to run and update relatively frequently, the current SwiftUI-based widget system required data ahead of time. This was a problem since it meant that widgets are technically not allowed to show recent data, but historical data instead.
I went on to provide widgets later on, but the functionality that Today Widgets provided has never quite been the same.
Version 2.0.1—2.2.0
The period after 2.0 was a time of stabilizing the app and building upon the foundation provided by the rewrite.
It was during this time that Swift introduced its Concurrency system (also known as async/await). This allowed for easier concurrency across the app and far fewer bugs, since Swift Concurrency sidesteps the “values over time” semantics of Combine when all you need is a single value or failure.
I introduced a few minor features and kept refining the app, but otherwise nothing major happened during this time.
A good foundation for the future
I always have a full backlog of ideas of where to take Bandwidth next. This is of course also due to all the feedback I get from users.
At the end of 2023, I decided I wanted to take Bandwidth to the next level. Stay tuned for Part 3 on how version 3 came to be, how it turned out, and what the future has in store for Bandwidth!