Maven plugins are used to copy all the project dependencies into a folder, generate a slimmed-down JVM, and then generate a platform-specific installer. The pom.xml is heavily commented!
Here are the folders unique to this project:
dependency
- all of the jar files declared by your Maven project, including the jar containing your codeinstaller-work
- the platform specific working files generated by jpackage.- Wix Toolset files on Windows
- Script Editor on macOS.
jvm-image
- Platform-specific, trimmed down JVM.packaging
- Platform-specific commands, filtered by Maven and fed to jpackage.
Standard Maven folders:
classes
- generated by the javac compiler, contains your compiled code.generated-sources
- side-effect of the javac compilermaven-archiver
- side-effect of Maven execution.maven-status
- side-effect of Maven compiler
There are a LOT of different flavors of Linux out there. I've provided the Ubuntu build more as an example of how the GitHub Action works, but I can't diagnose or trouble-shoot your Linux build (unless it's a consulting engagement). Feel free to post these in discussions!
I will note, however, that much of the Linux trouble I have seen comes from some of the included integration
demonstrations. Try commenting out the loading of demo plugins in BaseApplication.java
- specifically the loop that
loads the plugins.
In theory, the Exception handler in the plugin loader code should catch the exceptions. In practice, on a few flavors of Linux something dies with a native exception that takes it all down.
I get more support/issues for Linux builds than anything else, often for distros I've never heard of... which is cool but not something I'm really set up to deal with (short of paid consulting). That said, every Linux support issue so far has been resolved pretty easily by folks posting Maven or application log files in the discussion group. No promises, but go forth and post!
The current GitHub Workflow for the Linux build runs on a GitHub Ubuntu instance, and by default it generates a amd64.deb file. jpackage supports other distribution formats, including rpm, so if you want a different packaging format you can tweak the GitHub Action for the Ubuntu build and the jpackage command for Unix to generate whatever you need. As long as you can find the right combination of configuration flags for jpackage and can set up the GitHub Actions runner to match, you can generate whatever packaging you might need. If you need, you could set up several combinations of Maven profile and GitHub Action to generate as many different builds as you wish to support. For example, you could support generating macOS .dmg and .pkg files, Windows .msi and .exe, Linux .deb and .rpm in several different binary formats.
This template now uses the Liberica JDK build which includes JavaFX. This simplifies the developer experience and configuration over the old version of this template. I've created a branch for those that wish to use the Java 17 + bundled JavaFX template, but going forward I think the Liberica build is preferable for most JavaFX developers.
One nice side-effect is that I can eventually include a demo in this template illustrating the use of the JavaFX web module - basically an embedded web browser, similar to how Electron embeds Chromium to allow web developers to create desktop applications using browser technology. GitHub templates have an (undocumented?) limit
A: First, make sure you set a custom Windows installer UUID for your project, as described in the pom.xml!
This UUID is used to uniquely identify the app as YOUR app by the Windows installer system, and is critical for allowing users to seamlessly upgrade. You can quickly grab a UUID of your own and pop that value in instead. By default jpackage will generate a UUID automatically, but this automatic UUID is easily regenerated with minor changes to your application, breaking the Windows installer upgrade chain.
The Windows GitHub workflow for this project downloads the Wix Installer toolkit and adds it to the path to automatically build the Windows installer. On your local dev machine just install WiX Toolset locally instead - it'll be a lot faster.
Can I generate macOS installers on Windows, or Windows installers on macOS? Or macOS/Windows on Linux?
Not locally, but this project uses GitHub workflows to generate macOS and Windows ( and Linux) installers in the cloud regardless of your development platform. This means that (for example) you could do your dev work on Linux and rely on the GitHub Actions to generate macOS and Windows builds. If you need help, reach out to ChangeNode.com.
You still should (of course) do platform specific testing on your apps, but that's a different topic.
No. If that is something you need help setting up, feel free to reach out for help.
Some developers just ping the GitHub Releases API or even just a file on a web server and present an in-app UI notification to let users know if there is a new version available.
You might want to check out Sentry for crash reporting. This is a busy space and things move fast.
Ok. Check out JPackageScriptFX - the original shell scripts used as a reference when I initially started work on this project.
Sure - here's my personal list of cool JavaFX resources, which includes links to a few other big lists of resources.
If you are not familiar with the standard Maven build lifecycle, you are highly encouraged to review the documentation "Introduction to the Build Lifecycle" to understand how Maven builds work.
The project also uses os-activated, platform-specific profiles for configuration - really cool for setting up platform-specific stuff.
Correct.
There were two previous versions of this template, and both strategies were discarded as impractical in the real world.
The first approach was to try to create a shaded jar (a single jar containing all of the project dependencies) and then use jdeps to create a module-info.java and add it to the shaded jar. This failed to account for things like multi-release jars and jars with service declarations. While it worked for trivial applications, it fell apart with more complex real world usage. In particular, attempting to integrate Spring Boot into the application caused many issues to appear.
The second attempt took a more sophisticated approach - using jdeps to automatically modularize all of the project
dependencies.
A new collect-modules
goal
was added. In brief, the plugin would walk through the entire Maven dependency tree and sort all of the declared
dependencies into folders. The dependencies that already were modularized (both basic and multi-release jars) went into
one folder, and ordinary non-modularized jars went into another. The plugin would then attempt to use jdeps to
automatically generate module-info.java and add the compiled module-info.classes into each jar.
Unfortunately, this also failed. There were numerous errors, such a circular references between libraries (e.g. slf4j and logback). Some jars would only work when jdeps generated open module-info.java files, and others would only work when jdeps generated module-info.java files with package level exports. Many, many jars would have large numbers of packages exposed, which mean that the resulting module-info.java files contained many, many entries. The error messages and the resolution for these messages were very, very confusing. The terminology around modules is unfortunately very inaccessible to a typical Java developer - for example, a "static" declaration in a Java module-info.java is used to denote a concept similar to the Maven notion of "provided" - but unfortunately jdeps fails to run if a needed module is declared as a transitive reference. Even if it's optional.
In the end, even with the plugin, the error messages and the resolution of those messages is just simply not something a typical Java developer can be expected to understand or fix.
Which brings us back to this project. The end result is effective the same - just change
the <jvm.modules>javafx.media,javafx.controls,javafx.fxml,java.logging</jvm.modules>
declaration in the pom.xml to
specify the JVM modules you need and just skip all trying to modularize your app.
For now, I would consider the creation and use of module-info.java to effective be a system programming interface for the JDK itself and system-level modules such as JavaFX itself, where the entire dependency tree is very carefully enforced - and likely includes native code. For ordinary developers, just enjoy the benefits of a trimmed down custom JVM and don't worry about it. After all the challenges working with (incorrectly written!) module-info.java files I found just in the Spring Boot dependency graph, I would highly suggest that maintainers for ordinary, non-native Java libraries remove their existing module-info.java files.
It's a pity, as I think that if jdeps, jlink, and jpackage were set up to me more user-friendly, I think it would be a very interesting system that might lead to slimmed down, cloud-friendly applications. For me, the acid test for Java module adoption is probably Spring Boot. It's very, very popular. From a technical standpoint, it uses technologies such as reflection that are often notoriously tricky when working with static compilation heavily. An end user should be able to simply start working with Spring Boot and at at most a few commands to their build process. Clearly projects such as Spring Native shows there is an interest in this space.