Xircuit Blog

Product updates, developer logs, and news from behind the scenes at Xircuit.

Multi-Platform Finish — and Where We Stand Today cover image

Multi-Platform Finish — and Where We Stand Today


Multi-Platform Finish — and Where We Stand Today

Several devices as a symbol for multi-platform Photo: Rawpixel (CC0 1.0), via Openverse

There are weeks in which the most exciting work stays invisible. No new feature on the screen, no new page in the app — just a build that suddenly no longer takes three quarters of an hour, but a few minutes. This was exactly that kind of week. And because it's also the last post in this weekly series, I want to do both: explain the fine-tuning that brought Xircuit back to iOS and Mac, and then briefly step back and look at what has actually taken shape over half a year.

The occasion was practical. Over the weeks, a silent cost item had crept into our release pipeline, eating time and money every single time without anyone consciously noticing it. Removing it was less a feature than a cleanup — but exactly the kind that removes the sort of friction that slows a project down in the long run.

The silent cost item in the iOS build

A release build for iOS used to have an unpleasant property: it had to compile every single assembly for arm64 up front — classic ahead-of-time compilation. That's the price of Apple not allowing a just-in-time compiler on the device — the code has to be fully translated in advance. In theory that's clean. In practice it was a silent, expensive step of roughly 39 minutes, every single time.

That hurt especially because this step ran on the macOS runners, and in most CI billing models those are charged at ten times the rate of Linux minutes. 39 minutes of AOT are therefore not 39 minutes, but effectively almost 400. For a build that ultimately produces an IPA that's no different from what a faster path would deliver. I looked away from this for a while, because AOT is simply the standard path — until it became clear that there's another path Apple explicitly allows.

The Mono interpreter as a way out

The solution is the Mono interpreter, and the idea behind it is elegant. Instead of compiling every assembly ahead of time, the interpreter keeps only a minimal core AOT-compiled and interprets the rest at runtime. This is App Store compliant, because no code is generated at runtime — it is only interpreted, not compiled. And the build becomes drastically cheaper as a result: roughly 39 minutes shrinks to a few minutes.

The trade-off is worth naming honestly: interpreted code runs slower than fully AOT-compiled code. For an app like Xircuit, whose hot paths lie in the network, the database, and the Blazor Hybrid rendering layer rather than in tight computational loops, this is a trade-off you barely notice. We're trading a bit of runtime performance for an order of magnitude faster and cheaper builds — and gaining, above all, the freedom to release more often and without a guilty conscience.

A lesson from a real release

Things got briefly uncomfortable with Mac Catalyst, and the lesson was instructive enough that I want to record it here. A Catalyst build produces a universal bundle that combines two architecture slices: x64 for Intel Macs and arm64 for Apple Silicon. Both are built separately and merged into a single binary at the end.

The catch: the interpreter has to be active on both slices. If you enable it on only one, the runtime configurations of the two slices diverge — and the merge into the universal bundle fails, because it's being asked to force two incompatible runtime setups together. This isn't theory, it's an observation from a real release run. The fix in the end was small — set the interpreter consistently for both x64 and arm64 — but finding it meant understanding the bundle merge step by step. Details like this appear in no tutorial, and that's exactly why they end up in a dev log.

A summit as a symbol for a milestone Photo: Hoach Le Dinh · StockSnap (CC0 1.0), via Openverse

The closing release

With the fast build behind it, the closing release could do what a good release is supposed to do: ship everything that had piled up in one clean cut. iOS and macOS came back onto TestFlight — after a phase in which the Apple targets had fallen behind for build-cost reasons, that's a noticeable step. Alongside that, the marketing matrix went live, that collection of industry-specific pages we'd been building over the previous weeks, as did the health and access features that had already been finished but not yet deployed in full breadth.

A release that bundles several weeks of work is always a bit nerve-wracking — many moving parts, one pipeline, a green or red result at the end. That the Apple jobs this time completed in minutes instead of three quarters of an hour made the whole run noticeably more relaxed. It was the first release to confirm the new build path under real conditions, not just in a local test run.

Half a year, in hindsight

Looking back from here, the arc of this series becomes visible. At the start stood the foundation: a single codebase built on .NET 10 and Blazor Hybrid, orchestrated via .NET Aspire, deployed on Azure. On top of that, week by week, came the layers that turn a scaffold into a product.

First the real health integrations — not as a demo, but as a connection to real data sources, with all the care that health data demands around privacy and security. Then billing, which is what first makes a product viable, including the ability for organizations to bill their own members. After that, support, because a platform without a way to help people remains incomplete. And finally access control, the step out of the pure software world into real doors and real hardware. Alongside all of that came the marketing layer that explains it all to the outside world.

After half a year, more than an app now stands. What stands is a foundation: seven industries, real health integrations, billing, support, access — carried by a single codebase and shipped on six platforms. That web, Windows, macOS, iOS, iPadOS, and Android all come from the same code was, from the very start, this project's bet. This week's fast iOS build is essentially the last missing confirmation that this bet pays off, without the Apple platforms becoming a special case.

I write this without pathos and without wanting to give the impression that everything is finished. Much still runs behind feature flags, some things still need to be verified on real hardware, and the list of things that can get better is long. But a foundation differs from a prototype precisely in that you can keep building on it without tearing it down again first. That is the point we've reached.

What's next?

That brings the weekly relaunch series to a close — the dev log continues whenever there's the next big piece to tell.


Comments

No comments yet. Be the first to share your thoughts!

Leave a Comment