I'd be curious to see if native image works at all...
# compose-desktop
s
I'd be curious to see if native image works at all with Compose... I suppose not but it's be cool as it'd improve both the startup time and the perf
same 1
c
Wait. I thought r8 was android only? Can I use that on compose desktop apps? Thanks Romain I will take a look at your sample. My personal goal would be to get down below 100MB. Especially since I'm hosting my app myself I would love to not have to pay large fees per download.
a
I’m curious to see examples where a Kotlin/Native Compose app runs smoother than in the JVM.
🤔 1
2
Other than startup, probably.
t
@Alexander Maryanovsky jvm startup is the biggest issue, that is what my users are mostly complaining about. Kotlin/Native starts up instantly, JVM takes a few seconds. The biggest issue affecting JVM performance on macOS is that universal binaries are unsupported. So my app always has to run as an Intel app, even on ARM systems. The Apple App Store needs a single (universal) binary, it is impossible to upload separate binaries. Testing shows that ARM binaries are better than Intel binaries on ARM macs. But unfortunately that is just not possible through the App Store. The Intel on ARM issue affects both performance and startup times. Startup time for my JVM app is ~5 seconds, and another few seconds to load the app. And then the first few clicks throughout are so slow that the app is nearly unusable. RAM/CPU usage is also high due to this. If you want, you can try this at https://testflight.apple.com/join/u1953sBd. Version 4.2.7 is JVM Intel. Version 4.3.1 is Kotlin/Native universal binary. (there is a demo option under advanced on the connect screen) However, even with a JVM ARM build on ARM mac the app is still not as smooth as the Kotlin/Native app. For example with window resizing the JVM app still stutters. Startup time is still worse than Kotlin/Native. So I decided to just go with Kotlin/Native as my app was already ported to iOS. Cinterop is also much easier now, and the whole JVM universal packaging is no longer blocking me.
1
CDS helps a bit with startup time, already using that in my JVM app. Still an open PR though: https://github.com/JetBrains/compose-multiplatform/pull/2080
a
Ok, so the problem is specifically that issue with the app store. Because a regular JVM ARM runs fast for me.
However, even with a JVM ARM build on ARM mac the app is still not as smooth as the Kotlin/Native app. For example with window resizing the JVM app still stutters.
I think that’s a problem unrelated to performance. It’s just an issue with how we draw the Compose content on the window. In the native version we use a different method because, unlike with JVM/Swing we own the window. This is something I hope to fix soon-ish.
❤️ 4
👍 2
c
@Thomas can you add another link for test flight? that one doesn't work and id love to test those two versions you have! I'm going to be shipping my app on my website so it will have separate download buttons for intel vs apple chip. but good to know that the apple app store needs a universal binary... i guess that would make the app even BIGGER!
t
@Colton Idle it seems TestFlight has some issues currently, Maybe it works tomorrow. If you dm me your apple ID I can add you manually if you want. On the App Store for iOS non-relevant architectures are stripped automatically. But it appears this is currently not the case for macOS App Store. In my case, the 110MB download size is of the entire Kotlin/Native universal binary (Intel + ARM). So actually the Kotlin/Native app download size is pretty similar to the JVM app (61.6 MB), but due to now packaging both architectures I ended up higher. To clarify: JVM Intel only: download size: 61.6 MB, install size: 128 MB Kotlin/Native Intel+ARM: download size: 110 MB, install size: 395 MB @Alexander Maryanovsky Great to hear that wil be fixed. I’m still using JVM on Windows of course so all improvements to JVM are great. Still, startup time is not the best, really wish that could be improved on JVM. But for macOS I have to use Kotlin/Native so I get the universal binary. The Intel JVM app on ARM is unfortunately not an option, it is just too slow.
c
Is that just all jvm apps that are slow? Like is there a possibility of compose for desktop improving here, or is it a hard limitation that every single other desktop app will face?
t
GraalVM could help for startup time. I guess it depends on the app whether startup time is important. Apart from the startup time JVM is not slow. It’s just unfortunate JVM does not support universal binaries
a
Startup isn’t that slow either, in my experience. Try my app and tell me if you think it’s slow: https://theorycrafter.pro
c
1.5-2 seconds before actual app is drawn. not too bad. but you do have text before that "Warming up..." so I wonder if I shouldn't count that time and instead when the text first appears. lol side note: how to get rid of the java icon?
a
The warmup is optional. I’m rendering some of main screens to an offscreen buffer to preload their classes and avoid a few hundred millisecond delay between a click and the screen showing.
But there is an option to cheat a little bit by showing a pure Swing UI first while loading Compose in the background and then showing Compose when it’s ready.
(which I’m not using)
n
I found this thread because I am facing this issue right now; I have a KMP project targeting Android, iOS, Desktop and Web - but I'm yet to release. As soon as I try to build a release for desktop (on an OSX device)
packageReleaseDistributionForCurrentOS
I get an application that crashes as soon as I start it because I use compose navigation with a
@Serialized
data object and the exception suggests I should apply the annotation and apply the plugin - which I have and it works in Debug. Where do I start? I can't even seem to find a place in my gradle files to add anything for
obfuscate
,
minify
or proguard.
n
I opened Romain's project and started stealing stuff from there, but great to get this resource 👍
m
I’d just like to add to this discussion that, according to my knowledge, you can upload separate Intel and ARM versions of a software to the AppStore IF you set the minimumSystemVersion to 12 which should not be a real constraint these days anymore.
Copy code
macOS {
    ...
    minimumSystemVersion = "12" // Allows pure ARM apps in the App Store.
}
I can’t find the source for that anymore but as far as I remember it was from an Apple engineer in a comment of a rejected submission. I don’t distribute my apps via the AppStore, so I can’t confirm this from my own experience.
👀 1
a
That’s a very important piece of information, if true.
m
I think this makes my statement a bit more official: https://github.com/JetBrains/compose-multiplatform/pull/4271
Here it is directly from Apple under Apple silicon-only apps: https://developer.apple.com/macos/submit/
thank you color 2
m
@Colton Idle My thread trying to integrate ProGuard and eventually sharing my config: https://kotlinlang.slack.com/archives/C01D6HTPATV/p1702294616584159
❤️ 1
m
One important aspect of size optimization is to pick only the Java modules which are actually needed for your application. The build process uses jpackage and jlink internally to build a minimal runtime for the distribution. There is a Gradle task to get some hints but in the end it is a bit of a try and error game. Example for one of my projects:
Copy code
compose.desktop {
    application {
        ...
        nativeDistributions {
            modules("java.instrument", "java.management", "java.sql", "jdk.unsupported", "<http://jdk.crypto.ec|jdk.crypto.ec>")
            ...
        }
    }
}
👀 1
m
Note that Conveyor scans all your jars with jdeps to try and throw out unneeded modules.
Ultimately though, we need to migrate to a more browser-like streaming model IMHO. Tree shaking/r8/etc is great for latency but hard to get right. And for startup, yes, GraalVM is a great solution if someone does the work to make everything nice and easy to consume (Conveyor supports native images to some extent too). But it's one of those things where everyone feels a bit of pain, but nobody feels enough to do the work to make native images really easy out of the box
👀 1
m
The Gradle task I mentioned above is
suggestModules
and it also uses
jdeps
internally (see https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-native-distribution.html#including-jdk-modules) but I have experienced that in all my projects
jdeps
was somewhat wrong and I had to add modules manually.
m
Yes, there's a lot of heuristics required, the output isn't used exclusively