Writing a modern cross-platform desktop app

The goal of this article is to outline some of the architecture & design considerations made while thinking about how we would implement the OONI Probe desktop apps. This is the result of research and experimentation with a variety of different libraries and approaches. For each part of the technical stack we will outline the rationale leading to our choices.

Requirements & design goals

Our primary goal with the OONI Probe desktop apps is to enable Windows and macOS desktop users to run OONI Probe network measurement tests without knowledge of the command line. These tests will use the Measurement Kit implementation of OONI tests.

R) Requirements

These are must haves. We will not consider options which do not meet these criteria.

  1. Windows support
  2. macOS support
  3. Auto-update of the application
  4. Must not require a web browser for using the application
  5. One-click installation, whatever that means on the target platform
  6. Mature technologies that have an established community and a history of production applications using them
  7. Ability to link to a C++ library (Measurement Kit)
  8. Open source

D) Desiderata

Below we list features or use cases that we would like to support, but they should not be the reason for excluding an approach or technology.

  1. Linux desktop support
  2. Command Line Interface (CLI) support
  3. Support older versions of Windows
  4. Web browser support (for IoT type deployments)
  5. Easy to integrate our existing ooni-components that are styled-components
  6. The learning curve of the technologies in question should not be too steep
  7. The technologies should be ones that we are already familiar with
  8. Minimal code duplication between the various platforms
  9. As native as possible look and feel

Technological selection

In this section we provide an overview of the technologies we considered and list the pros and cons for each of them. Finally, we explain our choice of technical stack for this project.

The possible combinations of software stacks pivot around two main approaches:

1. Everything is implemented using some cross-platform GUI toolkit (electron, QT, etc.)

Less duplication of code (D8) and likely less costly to maintain in the long run (one code base for all platforms).

2. Use the best solution available for implementing the UI layer for each platform (react-native-window or WPF on windows, gtk on linux, cocoa on macOS)

More native feel (D9) and depending on the technological choice we can maybe re-use some code from the mobile apps (for example the iOS code for macOS).

React Native Windows





React native macOS


Excluded this fairly early on in our analysis as the quality of the software is not stable and doesn’t have real world use (R6).

The Readme used to say:

“There is no success story for any RN desktop app yet, so it’s not proven by production use.”

It doesn’t say it anymore, but I still couldn’t find any success stories through some quick online searching, nor by asking in the public channel.

React native linux


We looked at this just for curiosity to see what the linux-verse was doing in this regard.

It’s unclear if it’s still being actively developed (R6), or if the project has been abandoned entirely. It appears to be very incomplete and lacks proper documentation

Windows Presentation Foundation


This is the de-facto standard for developing apps on the Windows platform. It’s superseded by the newer UWP, but the later only support Windows 10+.

Even though it’s unclear how open source it is, we decided to look into it nonetheless as the libraries for using it are included as part of any Window installation.



Universal Windows Platform


This has very similar pros and cons to WPF, except that it only supports Window 10+ (D3). It seems like the learning curve for it may be a bit less steep than WPF upon a cursory look at it, but since it doesn’t support Window 7 (the mostly highly used windows version as of date), we didn’t consider it.



The main benefit of using Cocoa is that we could re-use some of the code from the iOS app. In looking into this option we realized that a lot of the code would need to change to support the desktop use-case and could not be easily translated. Moreover, the benefit of having identical code-bases for Windows and macOS outweighs the benefit of re-using iOS code.

Since we only have one developer on our team with Cocoa experience, it made more sense to opt for another solution (also given the fact that we didn’t find a satisfactory native option for Windows).



The most successful current non-native stack for desktop app development world is to use electron to build cross-platform desktop apps.





Based on the considerations above in the Technological selection, we concluded that, for our use-case, the Electron architecture makes the most sense.

The stack we decided to use based upon it includes:


Architecture Chart

While we are still consolidating the overall architecture of the desktop apps, our strawman architecture is the above.

The basic idea is that we are in the process of building node.js bindings for Measurement Kit. OONI Probe CLI will depend on these bindings and the CLI interface will be used by the desktop app and the desktop app will communicate with it via an IPC channel.

The desktop app itself will be a react.js app (built with next.js) that will be packaged with Electron.

We hope you have found this post useful, if you have further questions or suggestions on our development choices, we encourage you to subscribe to the ooni-dev mailing list.