为不同平台创建独立的Java可执行文件,无需安装

为不同平台创建独立的Java可执行文件,无需安装,java,package,executable,java-11,Java,Package,Executable,Java 11,我已经使用jlink创建了一个Java应用程序运行时映像。我希望能够将该软件作为可执行文件发送到不同的平台。(最好在一个平台上构建,比如交叉编译。) 理想情况下,它将是一个单一的应用程序文件,用户可以双击启动,而无需安装任何东西 如何实现这一点?您可以制作一个安装程序来安装JDK和应用程序。使用类似于和的东西将应用程序设置为exe,对于Mac可执行文件,请遵循Oracle提供的本教程:最后: Minecraft使用这种方法,我不知道还有其他方法 如果你想制作可移植的应用程序,“make once

我已经使用jlink创建了一个Java应用程序运行时映像。我希望能够将该软件作为可执行文件发送到不同的平台。(最好在一个平台上构建,比如交叉编译。)

理想情况下,它将是一个单一的应用程序文件,用户可以双击启动,而无需安装任何东西


如何实现这一点?

您可以制作一个安装程序来安装JDK和应用程序。使用类似于和的东西将应用程序设置为exe,对于Mac可执行文件,请遵循Oracle提供的本教程:最后:

Minecraft使用这种方法,我不知道还有其他方法


如果你想制作可移植的应用程序,“make once run anywhere”类型的应用程序,那么我建议尝试一种不同的编程语言,如C#,它也需要.NET运行时,但嵌入Windows系统,而Java需要手动安装。

双击可在多个平台上运行可执行文件,需要事先向操作系统注册文件类型,或现有文件类型以了解如何处理代码

jlink将“所需模块及其可传递依赖项”静态链接到输出

这个问题没有跨平台的解决方案

在一个文件中包含所有平台是不可能的(或者换句话说,不可行),因为每个可执行类型(COFF、ELF…)都有不同的结构。您可以尝试使用通用批处理文件来启动适当的可执行文件,但在Windows上,这需要文本文件类型编码;从而毒害剩余的二进制代码

使用jlink和新的jmod文件格式将允许您在Java容器中存储本机代码,从而允许在单个预定义平台的单个可执行映像中嵌入本机JRE代码的入口点。

这个问题的另一面是安全问题。由于嵌入式JRE不受安全更新的约束,破解者可能会选择嵌入一个先前已知的有缺陷的JRE,从而将正确的漏洞暴露给未知的消费者

反病毒程序的预期响应是将所有未更新的嵌入式JRE标记为病毒。

另外,请查看。这不是一个真正的Java,但是,它在某些情况下可能会帮助您,比如简单的命令行应用程序

底层虚拟机是一个允许提前(AOT)的框架 在封闭世界假设下将Java应用程序编译为 可执行映像或共享对象(ELF-64或64位Mach-O)


是的,对于Java8,有两种方法可以做到这一点,使用javapackager工具或JavaFX Ant任务(实际上并不特定于JavaFX,而是随Java8JDK提供的)

下面是一个示例,使用Maven将应用程序打包为Jar,设置主类和类路径属性,并将所有依赖项复制到文件夹中

<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>

maven依赖插件
包裹
复制依赖项
${project.build.directory}/lib
maven jar插件
3.2.0
真的
${project.groupId}.${project.artifactId}.DemoCLI
下面是打包独立应用程序的Ant构建文件(适用于Windows的exe、OS X上的.app和.dmg、Linux上的.deb和.rpm)


从${Java.home}使用Java

据我所知基本正确。没有办法“生成可执行文件”,JVM总是必需的。安装程序可以自动完成安装JVM和任何所需库的某些步骤,这是OP所能做到的。@Strom是的,Launch4j只生成仅在Windows上运行的EXE。类似这样的东西使得Mac可执行文件(DMJ文件)可能存在。您的帖子提供了大量信息,介绍了如何打包Java应用程序,以便在不安装JRE运行时的情况下在Windows和Mac OS上双击运行Java应用程序。我有一个可移植的Java和python发行版。如果我要制作一个只有相对路径的程序,你可以简单地复制一个包含可执行文件的整个文件夹树,你就可以让它在任何x64 windows操作系统上工作。我从USB@work使用它。它非常简洁,尤其是python和PIP。但是,当他们真的可以安装运行时库时,谁会想要一个数GB的文件夹呢?@RoyM,Java在不同版本之间已经变得不兼容,一次只能有一个版本在系统范围内处于活动状态。导致一些程序运行而另一些程序失败。通过使用Jlink,无论安装的版本如何,程序都可以运行。我不会称之为“静态链接”-它更像是将所有内容打包到一个文件中。实际上
Jlink
允许在不安装Java的情况下运行应用程序。这是它的主要目的。@ZhekaKozlov,如果这是它的“主要目的”,为什么它针对的操作系统没有直接的选择?如果没有嵌入本机代码的jmod文件,jlink本身无法创建本机可执行文件。@Robert,“静态链接是链接器将程序中使用的所有库例程复制到可执行映像中的结果。这可能需要比动态链接更多的磁盘空间和内存,但速度更快,可移植性更强,因为它不需要在运行它的系统上存在库。“引用自”。因为每个正式的Java实现
<?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>