I have a Compose app on macOS which works nicely f...
# compose-desktop
m
I have a Compose app on macOS which works nicely from the IDE but when I package it as a DMG and then try to launch the app-image it dies without any message. If I try to open it from a terminal it tells me
Copy code
LSOpenURLsWithRole() failed with error -10810 for the file ...MyApp.app.
which is also not very informative. When I then manually run the contents of the created app-image as a Java program I get:
Copy code
Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-x64.dylib.sha256, proper native dependency missing.
	at org.jetbrains.skiko.Library.load(Library.kt:43)
	at org.jetbrains.skija.impl.Library$Companion.staticLoad(Library.kt:12)
	at org.jetbrains.skija.impl.Library.staticLoad(Library.kt)
	at org.jetbrains.skija.Path.<clinit>(Path.java:27)
The app-image contains both libskiko-macos-x64.dylib and libskiko-macos-x64.dylib.sha256. Does anybody have an idea what is going on here?
d
Hi Michael. Yes, Java 16 uses the Java Modules system (aka Jigsaw) which sees the once huge and monolithic JDK broken up into many modules.
Unfortunately the packager is not automatically aware which of those is needed to be packaged, and you need to additionally specify them in Compose packagers Gradle configuration.
Copy code
compose.desktop {
    application {
        ...
        nativeDistributions {
            ...
            modules("java.net.http")
☝️ I had the same error as you:
LSOpenURLsWithRole()
...that's because Java HTTP is missing and can be included with the above line.
modules("<http://java.net|java.net>.http")
❤️ 1
As for your second error; I've seen this before too, in my case it was because I'd mistakenly used the dependency
Copy code
api(compose.desktop.common)
instead of
Copy code
api(compose.desktop.currentOs)
...but it doesn't sound like this is the same in your case. You say you're running the contents of the App image manually; is this bypassing scripts that would otherwise be setting the JVM library path?
libskiko-macos-x64.dylib.sha256
would certainly need to be on the JVM's library path.
Re: the first issue; there's also a Gradle task called
suggestRuntimeModules
that can search the classes you're using and advise on the Java modules to include. I don't know how reliable it is.
m
You are my hero! It works now but the modules I had to add explicitly where:
Copy code
modules("java.base","java.naming","java.prefs","java.scripting","java.sql","jdk.jfr","jdk.unsupported","jdk.unsupported.desktop","<http://jdk.crypto.ec|jdk.crypto.ec>","jdk.localedata")
I found them by using
jdeps
on my original JavaFX application where I do the packaging more manually and therefore have more insight on what is going on. Its embarrassing but I should have known that because I have written a tutorial about that for JavaFX myself together with Dirk Lemmermann. (https://github.com/dlemmermann/JPackageScriptFX)
👍 2
As for the second, obviously unrelated issue, I run the app as a Java app like this:
Copy code
#!/bin/bash

APP_CONTENTS=build/compose/binaries/main/app/MapDemoDesktop.app/Contents

# This works only if the native commands are not stripped
#JAVA_HOME=${APP_CONTENTS}/runtime/Contents/Home

${JAVA_HOME}/bin/java \
-cp "${APP_CONTENTS}/app/*" \
-Djava.library.path="${APP_CONTENTS}/app/" \
-ea \
-Xmx2048m \
MainKt
d
Glad the modules issue is resolved 🙂 For 2nd; I assume then that
libskiko-macos-x64.dylib.sha256
can be found in
build/compose/binaries/main/app/MapDemoDesktop.app/Contents/app/
? Otherwise there's your problem.
m
The
suggestRuntimeModules
task also works. The list can then be shortened to
Copy code
modules("java.instrument", "java.prefs", "java.sql", "jdk.unsupported","<http://jdk.crypto.ec|jdk.crypto.ec>","jdk.localedata")
The last two had to be added manually and where not suggested. The first of these is needed for https connections.
d
Thanks - Good to know about
java.instrument
for HTTPS! I'll run into that sooner or later...
m
No,
<http://jdk.crypto.ec|jdk.crypto.ec>
I meant the first of the two which I added manually.
👍 1
d
Is that right though?
<http://jdk.crypto.ec|jdk.crypto.ec>
...
...you got there before me 🙂
m
This is because the crypto stuff is loaded dynamically when you try to open the first https connection and jdeps cannot find that by a static analysis. I learned that the hard way 😉
👍 1