A year ago, I announced that a cross-platform version of Enigma would be released. Since then, I’ve explored several scenarios. Finding a good programming language seemed simple at first: the most obvious choice appeared to be Go. An excellent language that is inherently cross-platform. However, there were two major challenges I needed to address:
- Accessing the Swiss Ephemeris (SE).
- Building a user interface.
The SE is written in C. You can integrate the SE’s C code into a Go application using an FFI (Foreign Function Interface). This incurs some performance overhead and requires converting data between C and Go, but it’s manageable. However, you’d need a C compiler available when compiling your program. This raised questions: Would it work on iOS and Android? Could it cause issues when submitting the app to the App Store?
To solve this, I attempted to rewrite the SE in Go using AI. While I believe it’s feasible, it would require an enormous amount of time—so I abandoned this effort.
Another issue with Go is the user interface. Many suggest using Flutter, but that typically involves running Go as a backend server. If you want a native approach, you’d still need an FFI between Go and Dart (Flutter’s language), which would handle all backend-frontend communication—a major drawback in my view. Additionally, Flutter is primarily aimed at mobile platforms, which I do want to support, but my current focus is on desktops.
An alternative for Go is Fyne, a UI framework written in Go. Fyne works well, but its capabilities are limited. Most Fyne examples showcase relatively simple applications. I began doubting Go and realized there was another option: C#, but using Avalonia instead of the standard WPF for the UI. Avalonia is an evolution of WPF, more efficient, and supports multiple platforms. C# is also cross-platform.
I noticed that a C#/Avalonia app on macOS runs with DLLs. The SE is also available as a DLL—but only for Windows. On macOS, you’d need to compile a dynamic library (a .dylib, macOS’s equivalent of a DLL) from the SE code. Even then, it’s unclear whether this would work on mobile platforms later.
Moreover, it remained uncertain how likely a C#/Avalonia app would be accepted into the App Store.
I made a list of my priorities:
- A good user interface that feels native.
- App Store acceptance.
- No platform-specific issues.
There are other factors, of course, like performance and testability, but I’m focusing on the problems I encountered. My conclusion:
- Avalonia offers a great UI but not a truly native feel for all platforms.
- Fyne falls short in terms of features.
- App Store acceptance is questionable for all alternatives.
- I still can’t avoid platform-specific issues with these solutions.
As a result, I decided not to use these alternatives. Researching, experimenting, and building prototypes took too much time. So, I’ve adjusted my goals. I aimed for a fully cross-platform solution, but after extensive research and experimentation, I’ve realized this approach comes with too many compromises. Instead, I’ve decided to focus on native development first, prioritizing quality and platform integration over universal compatibility.
The revised plan:
- MacOS/iOS First: I’ll develop the core application in Swift/SwiftUI, ensuring optimal performance and seamless integration with Apple’s ecosystem. (Swift can access the C-code of the SE).
- Windows Second: The Swift code will be adapted to C#/Avalonia for Windows, reusing logic where possible while accepting some duplication. This will happen in parallel to the macOs development.
- Android and Linux: Android and Linux support will be reconsidered once the desktop versions are stable, likely requiring platform-specific solutions.
This shift means maintaining separate codebases, but it guarantees better performance, smoother UI, and fewer cross-platform quirks. The trade-off is worth it for a polished product.