JDeploy – Deploy desktop Java apps as native bundles on Mac, Linux, and Windows
jdeploy.com
jdeploy.com
- Native installers for Mac, Windows, and Linux
- Build native bundles for all platforms from any platform (e.g. You don't need Mac to make a Mac app. You don't need Windows to make a Windows app, etc..)
- Auto updates. Your users automatically get the latest version on each launch
- Small installer bundle size (3mb compressed)
- No need to futz with Mac codesigning/notarization
- Instant download page so your users can download your app as soon as its published.
- Free, open source
Please take it for a spin, and let me know what you think.
Assuming I'd rather self-host instead of hitching a ride on npm - could it it still be useful, as a cross-platform bundle maker? What are the single points of failure for the curated JRE procurement? Is it npm, is it jdeploy, is it adoptium? All of them?
I've done dances like concatenating a zip to a pre-built nsis exe to get a windows installer from a Linux build server, jdeploy sounds like an interesting alternative!
I've seen some interest for self hosting, so it will likely be added. In an earlier iteration (I've been at this for a couple years), it was self hosted, but I found that npm brought a lot to the table and simplified things, so I focused on that.
> What are the single points of failure for the curated JRE procurement?
Here's the process. The launcher (written in C and Go) checks the npm registry to get the app's metadata (e.g. JVM requirements, versions, etc..). If the app needs to be updated, it will update it. If it needs to download a compatible JVM it downloads it. (But it reuses JVMs so if it already has one that meets requirements, it will use that). Currently it downloads from Azul. Used to use Adoptium but switched for JavaFX support reasons.
Any of these pieces could be switched out pretty easily (npm -> self hosting, Zulu -> Adoptium, or self hosted, bundled VM, etc..).
What Java framework(Swing, FX etc) would you recommend for a desktop Java app?
Up to you. Swing is old faithful. JavaFX will result in something that is "cooler" and more modern. Both are supported. If you select "JavaFX" in JRE requirements, it will automatically use a VM with JavaFX to run your app so there's no penalty in app size for using JavaFX.
If you are looking to target mobile, and also want to deploy to Desktop, you might want to check out Codename One. (Full disclosure: I work there).
JavaFX and Swing aren't the only games in town either. jDeploy is part of my desire to make Java a more compelling choice for desktop app development. I still think it is too complex and overwhelming for new comers who just want to make a desktop app. I have some thoughts on how to simplify this, but I'll save that for another thread.
Maybe I'm over-hyping it, but I really doubt there has been a UI toolkit with that much work behind in a long time (Maybe Cocoa and one of the last 3 iterations of UI toolkit on Windows had that many work hours, but Cocoa does not work in all OS and the Windows ones well ... :shrug:)
I've played with Compose for Desktop and it's basically the Android framework, but running on desktop, as you might expect... but the tooling is currently not anywhere as good as Flutter IMO... and the customizations to make apps look like actual desktop apps (rather than mobile apps on Desktop which is just horrible) is currently impossible because there's just no docs on how to do it or any library that helps achieve that that I could find... Flutter, on the other hand, has multiple "themes" that work well on Desktop... I was amazed to watch a YT video where a Flutter guy showed how he implemented a Windows 3.1- like theme for Flutter and re-created a really old app for a customer that, for users, looks just like the old one (which was a strong requirement by the customer!).
I struggle with the same thing. jDeploy solves one half of that (deploying javafx is no longer a struggle). I think there is still room to make creating new projects simpler.
A single main dependency (org.openjfx/javafx-control) and a plugin (org.openjfx/javafx-maven-plugin) and you're off to the races. I don't install JFX into the JDK at all (not even sure, honestly, if that's still a thing).
I have more problems with JDK 9 modules (which modern JavaFX seems to support, but good luck with much of anything else of size).
Since I am pretty much awful at GUI programming, I've made a lot more progress with FX on my home projects than Swing. It's no panacea, but it's been working for me.
The pain of JavaFX becomes apparent at deployment time. Installing in a small closed ecosystem is fine. Mass market with all the variance. Ugh.
"Develop with pleasure" is well and truly dead until they make the out-of-box experience FAST.
I am currently using IntelliJ heavily at work and I would agree it was too slow for a gigantic project we have... but there's literally no alternatives that work nearly as great (Eclipse, Emacs, VSCode, tried them all, they mostly can't even load a project like ours --- Eclipse can but it's a pain to index everything on re-builds)... but since I got a Mac M1 Pro, IntelliJ again feels light and snappy :D unfortunately, having the best hardware possible seems necessary now, as ever.
For app store builds, jpackage is probably the way to go.
How do you handle this? Are there hooks so that desktop apps can know to migrate state that's on disk?
When it downloads a new version, it doesn't overwrite old versions. You can have two versions installed simultaneously. They are kept in $HOME/.jdeploy/packages/YOUR-PACKAGE/VERSION
It is also possible to peg your app to a particular version so that it doesn't auto update. Other variations are possible too, such as only autoupdating minor updates. E.g. Update to 2.1 or 2.2, but not to 3.0. For simplicity, I haven't exposes some of that yet.
There are no hooks. When your app runs, it is always running a particular version of the app. If your app needs to "transition" its resources when new versions are run, then that is up to you. No different than if the user downloaded and updated your app manually.
Just glancing at the site, it really looks like this is something you put a bunch of effort into. I'll definitely check this out! So thanks.
Do JBundle'd apps support native full screen size (not just expanding to fill the size of the screen, which allows other app windows to appear in front/behind), and native keyboard shortcut behaviour?
An appropriate GUI toolkit should be able to integrate with the native fullscreen.
I briefly used the webview for java library [1] and it does the right thing because the browser handles it. JavaFX also supports [2] native fullscreen if appropriate integration is used. Not sure about Swing/AWT etc.
[1] https://github.com/shannah/webviewjar
[2] https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Sta...
I wonder if you won't run into trouble because of the Mac codesigning/notarization though. I think this poses a significant legal risk to you, as you are now distributing potentially malicious software signed with your certificate. Also I'm pretty certain Apple doesn't like this "code signing as a service" approach.
But hats off, cool project!
Thanks!
Are there any examples anywhere of malware that has slipped through the client-side XProtect pre-flight checks, but that the server-side notarization checks have caught? Most independent macOS security literature I've read implies that notarization and code-signing is more about retaining centralized control of the app distribution process, but does not actually contribute anything to the malware mitigation tools that have been built into macOS for a very long time.
The build number refers to your app version. The download page creates the bundle on the fly (but does cache) using the latest jDeploy release, so when I released the new version of jDeploy, the bundles in the download page are auto-updated. I thought of adding the jdeploy version number into the installer name, but it was getting pretty busy already, so I decided to just leave that off.
Btw, font on website hurts my eyes, not easy to read. Its a font you'd use only by exception ie. italic usage (e.g. a quote). Not for a whole website.
IMO this is moving back in the direction of the original WORA philosophy of Java. jDeploy is designed to be cross platform. No platform-specific build settings, to as much extent possible. After the death of Applets and WebStart, the new direction of bundle a JRE with every app - and rely on platform-specific 3rd-part tools to create the bundles never felt right to me.
Is the 3M a launcher to download JRE & .jar files on-demand?
You are a hero - I hope this project really takes off! I dare say this is even better than Java Web Start (before it became hopelessly broken).
Super risky and definitely not a good approach from a security perspective.
It's big business. They buy EV certs from what I've seen and no one in the industry cares about anything but the money.
> What happens when someone publishes some malware application using their wrapped and noterized installer
The installer application simply installs the app. It doesn't in itself run any of the app's code. The installed app doesn't need to be codesigned and notarized like it would if you had just downloaded it from in your web browser.
This works fine for many cases. A limitation is that apps built in this way can't be submitted to the app store. For that you would use jpackage or similar. But in most cases, this strategy is fine - and even better since it includes things like auto-updates.
Wait, then doesn't that mean Apple's intent there is broken? I mean if you can bypass its controls on installing unsigned apps by merely wrapping an unsigned (possibly malicious) app in a signed installer, then what's the point?
npm, pip, etc.. are CLI install tools. jDeploy supports CLI app distribution using npm also. But the key difference is that jDeploy provides double-clickable installers for the apps. If you're distributing a desktop app, it should be installable in the desktop (IMO). Making users go to the command-line to install the app is actually prohibitive for the average user. Even when your userbase is programmers, I find that making them go into the command-line loses them.
> Does the app installed this way get more permissions coming from a signed installer? I'm not familiar with OSX security model.
Since Catalina, you can't download and run a Mac app in any form unless it is signed and notarized. Using the signed and notarized installer allows you to get around this limitation.
https://github.com/JOSM/josm/blob/master/native/macosx/macos... is my macos script, https://github.com/JOSM/josm/blob/master/native/windows/win-... is the windows script, and for how it moves, see https://github.com/JOSM/josm/blob/master/.github/workflows/a...
You might want to consider spelling codesigning as two separate words. The meaning / interpretation “co-designing” might be more prevalent for some users when spelled together. :)
Some people (here and elsewhere) have expressed similar sentiments about NPM. What would be your preferred alternative? Self hosted? Github releases?
Originally I built it to be self hosted, but NPM was just so darned easy to work with and made the process smoother, so I focused on that. NPM is really just a CDN in this context.
Similar to GP I wouldn't be trusting NPM with this kind of thing. For the convenience factor of it though, you should definitely leave that in place.
Have there been some events that cast doubt on the trustworthiness of NPM? vs, say Github?
Then you'd be able to do the ol' "specify base url" and as long as that host answers appropriately it should Just Work ( also doesn't stop you from then having npm configured as the default ); source freedom without blowing up configuration complexity
Publishing on the other hand I don't have easy recs for that don't eventually result in a lot of special-casing; That said, npm, git-compatible, s3-compatible, and ftp-compatible would cover most use cases, I think? Beyond those deployment types, custom deployment needs may well be better suited to pay you for a support contract anyway? )
It worked this way in an earlier iteration. I just wanted to make it simpler. I'll probably circle back and re-enable some of the more custom setups.
It does allow to you generate the apps and installers locally, but they are still "connected" to the cloud (NPM) for downloading the actual jar files and performing updates.
For the Mac: Brew, or just a download from a website.
For Linux: Download from a website or PPAs.
Again if NPM works, just stick with it, even if it weird.
What will happen if malware is distributed like this?
I doubt Apple would tolerate such blatant code signature abuse.
Apple restrictions are not ideal but they're there for a reason.
Second coming of JNLP it looks like
> Second coming of JNLP it looks like
Yeah. JNLP always still felt a bit second class to me. The move to native bundles was, all in all, a good step, but the process was always too cumbersome.
Indeed! I never really understood how Sun screwed that part up so bad. It served a highly valuable need, but it seemed like they almost intentionally killed it by making the apps so awkward to deploy and manage from a security perspective it was non viable to use.
"You must have a Mac to make a Mac binary" has always been an annoying shortcoming of jpackage, especially for smaller or independent developers.
Congrats, and thanks. This is going to be very useful for many developers.
EDIT: I mean jlink - jpackage would be an alternative to creating installers, but jlink just packages the app with parts of the JVM it requires, which seems could make this tool better by avoiding the need so maintain JREs (which are deprecated) on the user's machine.
With jlink , you don't need to download a whole JVM, it's usually a much smaller distribution. I have a LogFX application I distribute after passing it trhough jlink and it's around 30MB.
Not really. Currently it supports Java 8, 11, and 17. For each of those there is a JRE/JDK option, and a JavaFX option. Plus some of these are subsets. E.g. An app that doesn't need JavaFX can still use the JRE with JavaFX. And an app that doesn't need the full JDK can still use the JDK.
> as others pointed out, downloading two apps from the samples already shows the problem).
This was just an issue with the installer not needing JavaFX so downloading a non-javafx JRE first - but then the app needing JavaFX, so downloading one with JavaFX. This is a special case that will be resolved in an upcoming release by making the installer use a JRE that is compatible with the app to avoid the double download.
Anyways these are "fixed costs". Only incurred on first install. And, even then, maybe not if a compatible JVM is already present. All of your updates go through without the baggage of a JVM.
If you need more specific control over which JVM you're using than this (e.g. a specific build version or distribution), then jlink is a good tool for that. Life is about tradeoffs.
1. npm solves a few problems here. By publishing to npm, the app is instantly available to be downloaded and installed by users.
2. Auto updating. The launcher will automatically check for updates on launch, and download them if any are found so that users are always working with your latest version.
I may add support for other CDNs - and originally I just had it so you self host. But npm removes a lot fo complexity. It only takes a minute to create an account, and then you can publish.
> I might suggest using native packages, especially on mac; something like a DMG or .package. > Relying on npm seems a bit awkward.
1. npm solves a few problems here. By publishing to npm, the app is instantly available to be downloaded and installed by users.
2. Auto updating. The launcher will automatically check for updates on launch, and download them if any are found so that users are always working with your latest version.
I may add support for other CDNs - and originally I just had it so you self host. But npm removes a lot fo complexity. It only takes a minute to create an account, and then you can publish.
> I might suggest using native packages, especially on mac; something like a DMG or .package
The trouble with DMG and .pkg is that they need to be codesigned and notarized individually - which means you need a Mac and an Apple Developer account. Using jDeploy you don't need a Mac, and you don't need to worry about codesigning. This is because the installer is already signed and notarized. This probably the biggest pain point that I wanted to solve with jDeploy.
With a pkg I would need a different pkg for every app - which would need to be codesigned. Then we're back at the "need a mac to build mac app" issue. I wanted jDeploy fulfill WORA to whatever extent possible.
- [0]: https://github.com/Folcon/fruit-economy/blob/185d49f120bac18...
I got a tar file, which, when expanded, gave me an app. I launched the app (who's name I do not recall), which proceeded to download a JRE...somewhere, and gave me (I think) another app.
I launched that app, it, too, downloaded another JRE (so it said), and then launched the Ensemble app.
The Ensemble app worked fine, but none of the source code from the samples was visible. I don't know if that's a packaging issue or not.
Where did it install the JREs?
The observation that it downloaded 2 JREs (one for the installer and the other for the app) is a rough edge that will be fixed in an upcoming release. The reason is that the installer itself is an app that was bundled by jDeploy. It required a JRE, but didn't require JavaFX. When you, then launched the actual app, which was installed, it needed JavaFX, so couldn't use the JRE that was installed for the installer app, so it downloaded a JRE with JavaFX.
I will be optimizing this so that the "installer app" will try to use a JRE that meets both the installer requirements and app requirements so it only needs to download one JRE.
Hope that makes sense.
I have a feeling that apple will have to wait their turn on this one. It's only a matter of time before the inevitable happens.
If he has problems with Apple, it would be unfair compared to what is possible with Automator.
Looking at it with Signet, I get:
SwingSet2 Installer-1.0.5_255W/SwingSet2 Installer-1.0.5_255W.app error -67023 invalid resource directory (directory or signature have been modified)
The JavaFX Ensemble 8 Installer-1.0.8_255X app opens, but the experience is very un-Mac-like: the app is really a custom installer, and it places an app in `~/Applications/jDeploy Apps` instead of the expected /Applications. The resulting application then doesn't have the expected
The Unarchiver didn't like the JavaFX Ensemble 8 Installer-1.0.8_255X.tar.gz file, complaining about not being able to extract the Resources directory.
In a previous iteration everything was designed to be self-hosted, but decided to focus on npm support because it made things much simpler. I'll be re-exposing the self-hosting, and private npm options as demand dictates.
> There is a way to control to what version auto updates?
Internally it supports some rich update rules. It is possible to generate apps that are pegged to a specific version (e.g. 1.0.7), or that will only update build updates (e.g. 1.0.), or minor updates (e.g. 1.). By default they don't update to pre-releases (e.g. 1.0.1-alpha.1), but this is configurable by the user.
I haven't documented this yet because I want to avoid confusion at the beginning as much as possible. There are dozens of variations that could be supported, but I'm trying to hit the 90% use case out of the box first...
> I need to avoid that the client app auto updates to the wrong version, before the server and the database are updated.
You could just bake that into your client (detect the server version). Alternatively, just wait until the server is updated before you publish the client update. This could be triggered in CI as well.
1) Can I run jlink somewhere in the build process?
2) Can I use a private npm repo like Verdaccio, or are there plans for other (non npm?) backends in the future?
No need. Just specify your JVM requirements and the launcher will automatically use (or download if necessary) a compatible VM. This allows JVMs to be shared between apps, and your app updates are much smaller since they don't include the VM bundled directly.
> 2) Can I use a private npm repo like Verdaccio, or are there plans for other (non npm?) backends in the future?
Right now it's pegged to the public npm repo, but I'll be exploring other options soon, including private repos, self hosting, GitHub releases.
Either way, really exciting stuff, we'll definitely have a play! Any plans for commercial features in the future?
I'll have to find out what kinds of features are of interest to commercial clients. I'd like to find some way to support continued development. Commercial features are certainly a possibility.
The idea is to fulfill the promise of WORA all the way to deployment. Everything is built and configured in a cross-platform way, and then is deployed as first-class native bundles on each platform.
I really will definitely try it out for my free-visit builder installer. If it works well like some have said, boy you saved my day ♥. Love
Can't you already do this with jpackage or graalvm to create native bundles?
At least with jpackage you already get an installer, versioning and upgradeability. I haven't tried graalvm'd native compiler but it should be possible as well.
With jpackage or graalvm you need a Windows machine to build your windows installer because it relies on 3rd party Windows tools for the installer. Likewise on Mac and Linux. Even worse, on Mac you need to Codesign and Notarize the app, which is painful every time.
> At least with jpackage you already get an installer, versioning and upgradeability.
With jDeploy, it will check for updates when the app launches, and will download them automatically, so your users are always on the latest version.
Me too... Me too.