Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create standalone Java executable for different platforms without installation

I have created a Java application runtime image using jlink. I would like to be able to ship the software as an executable to different platforms. (Preferably by building on one platform, like cross-compiling.)

Ideally, it would be a single application file that users may double-click to launch, without installing anything.

How can this be accomplished?

like image 591
NeradaXsinZ Avatar asked Jan 25 '19 20:01

NeradaXsinZ


3 Answers

Yes, as of Java 8 there are two ways of doing this, using the javapackager tool, or the JavaFX Ant Tasks (which aren't actually specific to JavaFX, and are provided with the Java 8 JDK).

Here's an example of packaging an application as a Jar, setting the main-class and classpath attributes, and copying all the dependencies into a folder, using Maven.

<plugins>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>${project.groupId}.${project.artifactId}.DemoCLI</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
</plugins>

And here is the Ant build file to package the standalone application (exe for Windows, .app and .dmg on OS X, .deb and .rpm on Linux).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>

<!--
 Uses the JavaFX Ant Tasks to build native application bundles
 (specific to the platform which it is built on).

 See https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/javafx_ant_tasks.html

 These tasks are distributed with version 8 of the Oracle JDK,
 Amazon Corretto JDK, RedHat JDK, probably others, though they
 do not seem to be the OpenJDK on Debian Linux

 -->
<project
    name="fxwebclient" default="default" basedir="."
    xmlns:fx="javafx:com.sun.javafx.tools.ant">

    <!-- In Java 8, java.home is typically the JRE of a JDK -->
    <property name="jdk.lib.dir" value="${java.home}/../lib" />

    <!-- Where to build our app bundles -->
    <property name="build.dist.dir" value="${basedir}/target/dist" />

   <echo>Using Java from ${java.home}</echo>

    <target name="default" depends="clean">

        <!-- get the ant-jfx.jar from the JDK -->
        <taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
            uri="javafx:com.sun.javafx.tools.ant"
            classpath="${jdk.lib.dir}/ant-javafx.jar" />

        <!-- Define our application entry point -->
        <fx:application id="demo" name="demo"
            mainClass="yourpackage.DemoCLI" />

        <!-- Our jar and copied dependency jars (see pom.xml) -->
       <fx:resources id="appRes">
            <fx:fileset dir="${basedir}/target" includes="*.jar"/>
            <fx:fileset dir="${basedir}/target/lib" includes="*.jar" />
       </fx:resources>

        <!-- Create app bundles [platform specific] -->
        <fx:deploy nativeBundles="all"
            outdir="${build.dist.dir}" outfile="DemoWebClient">

            <fx:application refid="demo" />
            <fx:resources refid="appRes" />

        </fx:deploy>

    </target>

    <!-- clean up -->
    <target name="clean">
        <delete dir="${build.dist.dir}" includeEmptyDirs="true" />
        <delete file="${basedir}/target/${ant.project.name}.jar" />
    </target>

</project>
like image 69
guymac Avatar answered Oct 19 '22 23:10

guymac


What you're describing is what's called a native executable. There are programs that will wrap your Java application into an executable file but because Java runs it's code on the Java Virtual Machine (JVM), your users will need to have it pre-installed for your program to work out of the box. You can code an installer for your application in something like C++ or C# (C# runs on the .NET Runtime which comes pre-installed on all Windows machines) that installs the JVM and possibly your application alongside it, and then compile that code to a native executable. That way, the end user doesn’t need to go looking around for Java downloads. This is the approach that Minecraft takes I believe.

Wrap your Java executable into a native executable using any of:

  • Launch4J (Windows)

  • Oracle Docs (MacOS)

  • Discourse (Linux)

  • Quarkus (native executable, no installer)

  • Warp Packer (self-extracting executable, no installer)

like image 36
6 revs Avatar answered Oct 19 '22 23:10

6 revs


Also, have a look at SubstrateVM. This is not a true Java, however, it may help you in some cases like simple command line applications.

Substrate VM is a framework that allows ahead-of-time (AOT) compilation of Java applications under closed-world assumption into executable images or shared objects (ELF-64 or 64-bit Mach-O).

like image 1
ZhekaKozlov Avatar answered Oct 19 '22 21:10

ZhekaKozlov