Jetpack Compose... on the Desktop
The Awesome Android newsletter’s issue #201 pointed out a very interesting Gerrit entry related to Jetpack Compose, hinting at a future desktop offering. This possibility is something that I have been tracking for a few months now, so let’s explore what may be going on here.
Expecting Actual Code
When I was poring over the early dev
builds of Jetpack Compose, I noticed
that some elements had commented-out expect
and actual
keywords. For example,
Canvas.kt
had commented-out expect
keywords and
AndroidCanvas.kt
had commented-out actual
keywords.
Those keywords are tied to Kotlin/Multiplatform (KMP for short).
In KMP, you have Kotlin code that can run across all platforms (Kotlin/Common).
That code can expect
an API that, for any given platform, something else will supply
the actual
implementation of that API. For example, you can have common Kotlin code
that will expect
Android and iOS modules to implement the actual
version of the expected
API, using platform-specific stuff to do so. This is a bit reminiscent of how your
main/
source set in an Android app can “expect” that each of your product flavors
have an “actual” implementation of some class (e.g., a strategy pattern implementation
tied to that flavor).
Since the keywords are commented out, we do not really need a KMP setup to be able to build or use Compose. And there are fairly few occurrences of these commented-out keywords, so this may have been just a form of documentation, leveraging KMP keywords for showing the relationship between functions.
But, somebody was thinking about Compose on multiple platforms, at least to some level.
Android as API
We often say that our code depends upon Android. However, much of the time,
that is really shorthand for “our code depends upon Android APIs”. We use android
classes and expect them to do what we want them to do. Exactly what those
implementations are and how they accomplish their aims usually is beyond what we
really care about as app developers.
As a result, as long as we satisfy the symbols that we reference and that the compiler needs, exactly what sits behind those symbols is immaterial, so long as our code works.
Android developers take advantage of that on a daily basis:
-
Your
compileSdkVersion
is used to identify a JAR containing all thepublic
symbols from the Android SDK. But the actual implementation of all the Java methods is simplythrow new RuntimeException("Stub!")
. The real implementation of Android is added to our classpath at runtime; theandroid.jar
that we compile against is not packaged in our APKs. -
Robolectric, in the end, is an implementation of a slice of the Android SDK that does not have any Android ties. Robolectric’s implementation gets used in unit tests that run on the JVM, not on Android, allowing us to test a bit more of our code than we might otherwise, while also allowing us to avoid having to roll our own mocks of those
android
classes.
What That Gerrit Entry Shows
The main Gerrit link
from the Awesome Android newsletter represents a KMP project, targeting the JVM desktop.
In there, desktopMain/
is a source set for code that will be used for desktop apps.
And in that source set, we see class names that look an awful lot like a subset
of the Android SDK, such as android.content.Context
and android.view.View
.
The implementations of those classes look nothing like Android. For one, they are all
in Kotlin, and last I checked, the AOSP framework classes are still in Java.
And those classes implement a tiny subset of the real framework APIs. Right now, the
desktopMain/
implementation of Context
, for example, is 43 lines of code…
including the copyright header comment. There are individual methods in the
real Context
class that are longer than that.
The objective appears to be to satisfy the compiler to allow Compose code to build an Android app, with class and function implementations that use desktop Java instead of Android.
The actual UI is rendered by a SkiaWindow
, which relies on JetBrains’ Skija project,
which offers Skia bindings for Java. Skia is an open source
2D graphics library, one that powers rendering in Android, Chrome OS, and in browsers
like Chrome and Firefox.
So, at least at an experimental level, Google appears to be working on getting Jetpack Compose to support desktop apps, as well as Android apps.
Implementing “fake” Android framework classes may be somewhat of a stop-gap.
If Google elects to take Jetpack Compose more fully into KMP, uncommenting
those expect
and actual
keywords and expanding upon them, then the desktop code would switch
to providing the actual
API that Compose is trying to expect
.
Of course, right now we have no idea if Google will ever bring this to fruition. For all we know, this is just an experiment, one that will never see the light of day (beyond blog posts like this one). We know that it is actively being worked on — one of the developers uploaded a new patchset while I was writing this post.
Regardless, implementing something like this is likely to happen. I have seen other developers start to poke at this sort of thing, and I considered doing it myself. It’s possible that all of those efforts will come to naught as well, but there’s a decent chance that somebody will succeed.
If Jetpack Compose becomes Google’s recommended UI approach for Android, having the ability to also develop desktop apps from much of the same code base is a nice value-add, at minimum… and possibly much more.