State of Compose 2023 results are in! Click here to learn more
Published on

Compose Desktop in Production: my experience and gotchas

Authors

Featured in Android Weekly #551

In this article I will share my experiences using Compose Desktop building Ubidrop, a file sharing app and will give you an idea whether this technology is a good fit for your business.

What is Compose Desktop

According to Jetbrains, Compose Desktop promises fast reactive desktop UI development using Kotlin on desktop applications.

Compose Desktop generates a JVM app and its UI is powered by everyone's favorite Compose. This has both benefits and disadvantages compared to building native apps which we will cover next.

What kind of applications can you build using Compose Desktop

The great thing about Compose Desktop is the ability to write code once and create apps for different platforms. This includes MacOS, Windows and Linux desktops.

Compose Desktop shines when it comes to applications that do not integrate with the system. As a matter of fact the development experience is great as you use a modern UI framework to build your UI and creating windows is pretty straightforward.

Compose Desktop and system integration: Not great

Keep in mind that you are not going to get the full native experience using Compose Desktop. Any sort of system integration does not work as you might expect. There is the Tray composable which is used to create native looking Tray menus. To my experience it works somewhat alright for MacOS, but it looks really dated on Windows platforms. I have not tried it out on Linux. The customizations are too limiting. You can only set text items without any icons.

Overall, any integration with the system is extremely limiting. Compose Desktop does not support rich notifications. You can display notifications but you cannot dismiss them programmatically. You cannot set actions to the notifications or customize their icon or sounds. The alternative solution to this is implementing your own Notification system.

This limitation also comes to other system functionality such as sharing content to your Compose app by right clicking desktop files > Share to... actions which are typical to Desktop applications.

Using Native APIs is not supported

Using Native APIs seems really hard to do. It is in theory possible to use native APIs via a Java Bridge but the documentation and material to do this online seems limited and dated. Even if you are able to use the Java Bridge you should be able to understand each different platform's APIs and language to do the wiring.

As a solo developer building my own products, this was incredibly limiting. I could push towards trying to figure out how to create a bridge between Compose Desktop and Native but the effort put into this does not justify the return. In my case I would rather focus on improving my product instead of fighting the technology I have to work with.

Packaging tools are not there yet

Compose Desktop comes with a gradle plugin which is used to package your app for different operating systems. Right now the plugin requires you to build the app from each operating system on that respective operating system (ie you need to be building on Windows to create a Windows executable).

The customization options of the plugin seem great at first but in reality they are lacking. For MacOS builds, the plugin provides a way to notarize your app, which is a process required by Apple to distribute MacOS applications. However, you can only notarize pkg or dmg files using the plugin. That might have been alright (I would love to see a zip version instead) if you could choose the icon for the dmg files. Right now any dmg files created using the Compose Desktop will have Java's Duke as the icon:

If you are building a MacOS app, then creating a Universal app is not currently supported. Creating different versions of the app is tricky too, as this is not documented and the simplest solution is to create an Intel version of the app and distribute that instead.

The level of quality is similar in the Windows distributions. You cannot customize the looks of the installer and once the installation wizard is over, you cannot add an option to start your app once it is done, which makes user onboarding harder.

There are alternatives to the default packaging tool that comes with Compose Desktop. Jetbrains recommends using a tool called Hydraulic Conveyor. I found the tool to be much more documented compared to the default one and building different versions is much simpler. The good thing is that they are also supporting auto-updates but it doesn't seem you have much control over their UX. If you do not want to rely to any 3rd party tooling, have a look at jpackage which is a tool for creating executables of your Java applications.

Expected Desktop functionality is not there

I feel like Compose Desktop is missing functionality that you might expect from a desktop framework. For example, there is no way to auto-update the application. There are solutions out there for updating Java applications but this means that I need to learn yet an other tool on how to do this.

Usually, MacOS apps prompt you to move them to the Applications folder when they are launched. Such functionality is missing from Compose Desktop, along with an API to start the app on startup. Little things like that make the user experience of Compose Desktop apps lacking.

The state of documentation and community

As of December 2022, the official documentation of Compose Desktop lives on the Compose Desktop Github Repository. It can help you a lot getting started with the technology. In case you need more help, the #compose-desktop channel on Kotlinlang Slack is the place to go. It takes a while to get your questions answered as there aren't that many people using the technology.

Cross platform alternatives to Compose Desktop

In case you feel Compose Desktop is not for you, there are other cross platform frameworks you can use. Electron is one of the most popular cross platform framework to use but these days it feels dated. Tauri appears to be the modern alternative to Electron and I have heard some good things about it, but haven't tried it out. Lastly Flutter is gaining popularity and I heard good things about its bridges to native functionality.

An alternative to cross-platform frameworks: Kotlin Native

One technology that seems appealing for my business is the use of Kotlin multiplatform. You should be able to write your UI natively for each platform and share the business logic using Kotlin. The great thing about this is that Kotlin native provides bindings to Native APIs using Kotlin. This means that you should be able to use Kotlin Multiplatform to create libraries for each platform you would like to target that holds your business logic, and use Kotlin Native to write the platform specific code in Kotlin. This solution would require writing your UI using each platform's language and tooling and this would give you full access to the platform's APIs and integrate to it.


That was my experience using Compose Desktop to build Ubidrop and I hope it helped you decide whether you should pick the technology for your next project. Compose Desktop shines when it comes to apps that do not integrate with the system. If you are okay with that and not being able to modify the app-updates flow, it seems like a good choice. If you are looking into integrating with the system better, other cross platform frameworks might be a better idea. The option of going native but sharing business logic across different platforms is also an alternative.

PS: This article was originally called 'Compose Desktop in Production: my experience and gotchas'. Turns out the Jetpack brand is under Google's, while Jetbrains (the company building Compose Multiplatform) is using the Compose branding and there is no such thing as Jetpack Compose Desktop.