如何将JRE捆绑到Java应用程序的EXE文件中?Launch4j提示“运行时缺失或损坏”。

43

我是Java编程的新手,但大致了解一切如何运作。我想将一个jar文件和jre放进Windows可执行文件(exe)中,这样当我分发它时,客户端就不需要安装JRE。我应该使用什么程序?

我有launch4j,它似乎正好符合我的要求,但当我尝试运行应用程序时,出现“此应用程序配置为使用捆绑的Java运行时环境,但运行时环境丢失或损坏。”

我希望我的应用程序只是可运行的exe,而不是安装程序。至少,有人能向我展示如何正确地将JRE与launch4j捆绑吗?


当您使用launch4j时,有什么问题无法解决? - Code-Apprentice
我收到错误信息:“该应用程序被配置为使用捆绑的Java运行时环境,但运行时环境缺失或损坏。” - MagicGuy52
请编辑您的问题,描述您尝试使用L4J的具体步骤以及发生了什么事情。 - Code-Apprentice
@DaveJarvis 你有没有看过launch4j?根据它的网站介绍,它是一个跨平台的工具,可以将Java应用程序包装成轻量级的Windows本地可执行文件,并且可以配置为使用捆绑的[JRE]。看起来它符合OP的需求。 - Miserable Variable
1
它确实可以,但它是一个安装程序。我没有看到创建非安装程序的exe的方法。 - MagicGuy52
显示剩余2条评论
9个回答

43

我唯一能够捆绑JRE的方法是使用Launch4JInno Setup Compiler

首先,在输出文件(.exe)的同一目录下创建一个jre6文件夹(例如)。

然后将JRE从您的系统复制到您的jre6文件夹中。

然后打开Launch4J并设置捆绑的JRE路径 - 只需输入jre6。然后单击“构建”按钮(显然,您需要在输入所有其他参数之后 - 但您在JRE选项卡本身上需要输入的唯一值是捆绑的JRE路径值)。

我原本以为这样可以正常工作,但如果您将.exe文件移动到新位置(因此它不再与您的jre6文件夹共存),则在尝试运行应用程序时会出现此应用程序已配置为使用捆绑的Java Runtime Environment,但运行时缺少或损坏错误...

"I've been playing around with this all day and there was no way I could get Launch4J to include the JRE in the .exe file. Really poor in my opinion, as their documentation does not seem to allude to this issue at all."
所以我尝试解决这个问题,使用了Inno Setup Compiler (ISC)。该应用程序用于将您的.exe文件打包为Windows Installer文件。因此,我在ISC脚本中添加了一个设置,将JRE复制到安装程序包中。我添加到脚本(在[Files]部分)的行是:
Source: "M:\Netbeans\MyApp\jre6\*"; DestDir: "{app}\jre6\"; Flags: recursesubdirs createallsubdirs

我用了一些绕路的方法,但是它解决了问题。

重复以上步骤,你应该就可以解决问题了。


有没有办法用Maven完成所有这些操作? - Marcus
抱歉,我不熟悉Maven。你最好发布一个新的SO问题。 - ban-geoengineering
1
我不理解你的解决方法。我的NetBeans项目文件夹中没有jre6。在C:\Program Files\Java中有一个jre6。此外,如果NetBeans项目用于创建本地exe,则它(NetBeans)在内部使用Inno Setup创建安装程序,如果执行该安装程序,则会将jre文件夹放置在用户AppData\Local中,例如:C:\Users\Ed Sowell\AppData\Local\TryNativePackaging\runtime\jre。 - Ed S
此外,Inno Setup Compiler 现在被称为 Inno Setup,可以通过 http://www.jrsoftware.org/ 下载。 - ban-geoengineering
2
对于像我这样想要将launch4j + inno setup集成到gradle任务中的人,这可能会很有用: https://blog.heckel.io/2014/05/29/gradle-create-windows-installers-debian-packages-manage-a-ppa-and-optional-sub-projects/ https://github.com/syncany/syncany/blob/develop/gradle/innosetup/INNOSETUP.md - Alex Rodriguez Lopez
显示剩余10条评论

8

将JRE打包成EXE的简单方法是使用Lanch4j打包器中提供的Wrap工具。

warp-packer --arch windows-x64 --input_dir mycrt --exec run.bat --output single.exe

在启动exe文件后停止命令行窗口。

editbin /subsystem:windows

warphttps://github.com/dgiagio/warp

editbin:由VS安装

演示:

在此输入图片描述

在此输入图片描述


这对我非常有效。根据这里的信息,我编写了使用jlink + warp + maven + javafx创建可执行JavaFX窗口应用程序文件(.exe)的说明,详见我的回答如何在Java中创建独立的.exe文件(无需安装程序和JRE即可运行) - jewelsea

3

Inno Setup的打包JRE解决方案

为了实现应用程序jar的JRE捆绑解决方案,我创建了一个Inno Setup脚本,该脚本:

1)将JRE复制到安装exe文件中

2)使用捆绑的JRE执行相当于终端命令:java -jar myjar.jar

首先,我将JRE复制:

#define MyJREPath "C:\Program Files\Java\jre1.8.0_191"

[Files]
Source: "{#MyJREPath}\*"; DestDir: "{app}\runtime\jre\";  \
        Flags: ignoreversion recursesubdirs createallsubdirs;  

我遵循这里展示的目录结构约定:https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/self-contained-packaging.html 要运行等同于java -jar myjar.jar的命令:
[Run]
Filename: "{app}\runtime\jre\bin\javaw.exe"; Parameters: " -jar myjar.jar"; \
          WorkingDir: "{app}\app\"; \
          Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; \
          Flags: postinstall skipifsilent   

(n.b. java.exe 在终端中运行,javaw.exe 则在没有终端的情况下运行)
桌面快捷方式需要有正确的文件名、参数和工作目录:
[Icons]
Name: "{commondesktop}\{#MyAppName}"; \
      IconFilename: "{app}\app\{#MyAppIcoName}"; \
      Filename: "{app}\runtime\jre\bin\javaw.exe"; \
      Parameters: " -jar myjar.jar"; \
      WorkingDir: "{app}\app\"; \
      Tasks: desktopicon

[Tasks]
Name: "desktopicon"; \
    Description: "{cm:CreateDesktopIcon}"; \
    GroupDescription: "{cm:AdditionalIcons}"; \
    Flags: unchecked

为了锦上添花,在处理捆绑JRE和不捆绑选项时,我使用预处理器IF语句(在每个脚本部分中都有重复)来检测脚本是否具有空的MyJREPath。如果MyJREPath不为空,需要使用捆绑的JRE解决方案,则使用上面的代码;或者,如果不需要捆绑解决方案,则使用更多“正常”的代码,如Inno Setup示例或其向导生成的代码。这是IF语句:
#if MyJREPath != ""
    ; bundled JRE required

#else
    ; bundled JRE not required
#endif

这是我大部分脚本的组合:

        ; Script generated by the Inno Setup Script Wizard.
        ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!


        ; some more #defines here

        #define MyAppExeName "javaw.exe"
        #define MyJREPath "C:\Program Files\Java\jre1.8.0_191" 
        ;#define MyJREPath ""




        [Setup]
        ; NOTE: The value of AppId uniquely identifies this application.
        ; Do not use the same AppId value in installers for other applications.
        ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
        AppId=XXXXXXXXXX
        AppName={#MyAppName}
        AppVersion={#MyAppVersion}
        ;AppVerName={#MyAppName} {#MyAppVersion}
        AppPublisher={#MyAppPublisher}
        DefaultGroupName={#MyAppPublisher}
        AppPublisherURL={#MyAppURL}
        AppSupportURL={#MyAppURL}
        AppUpdatesURL={#MyAppURL}   
        DefaultDirName={pf}\{#MyDefaultDirName}
        DisableProgramGroupPage=yes
        LicenseFile={#MyInnoSetupDir}\system\{#MyLicenseFile}
        OutputDir={#MyInnoSetupDir}

        #if MyJREPath != "" 
          ; run app with bundled JRE
          OutputBaseFilename={#MyAppName}-{#MyAppVersion}-bundledJRE-setup
        #else
          ; run app without bundled JRE
          OutputBaseFilename={#MyAppName}-{#MyAppVersion}-setup          
        #endif 

        SetupIconFile={#MyInnoSetupDir}\{#MyAppIcoName}
        Compression=lzma
        SolidCompression=yes  
        AppComments={#MyAppName}
        AppCopyright={#MyAppCopyright}  
        UninstallDisplayIcon={#MyInnoSetupDir}\{#MyAppIcoName}
        UninstallDisplayName={#MyAppName}
        WizardImageStretch=No
        WizardSmallImageFile={#MyInnoSetupDir}\{#MyAppBmpName}



        [Languages]
        Name: "english"; MessagesFile: "compiler:Default.isl"
        ;Name: "german"; MessagesFile: "compiler:Languages\German.isl"

        [Tasks]
        Name: "desktopicon"; \
                Description: "{cm:CreateDesktopIcon}"; \
                GroupDescription: "{cm:AdditionalIcons}"; \
                Flags: unchecked
        Name: "quicklaunchicon"; \
                Description: "{cm:CreateQuickLaunchIcon}"; \
                GroupDescription: "{cm:AdditionalIcons}"; \
                Flags: unchecked; OnlyBelowVersion: 0,6.1

        [Files]
        ; bundle JRE if required
        #if MyJREPath != "" 
            Source: "{#MyJREPath}\*"; DestDir: "{app}\runtime\jre\";  \
                Flags: ignoreversion recursesubdirs createallsubdirs;       
        #endif      

        ; copy jar and all files  
        Source: "{#MyInnoSetupDir}\*"; DestDir: "{app}\app\"; \        
                Flags: ignoreversion recursesubdirs createallsubdirs


        [Icons]
        #if MyJREPath != ""
          ; set up icons with bundled JRE
          Name: "{commonprograms}\{#MyAppName}"; \
                  IconFilename: "{app}\app\{#MyAppIcoName}"; \
                  Filename: "{app}\runtime\jre\bin\{#MyAppExeName}"; \
                  Parameters: " -jar {#MyJarName}"; \
                  WorkingDir: "{app}\app\"
          Name: "{commondesktop}\{#MyAppName}"; \
                  IconFilename: "{app}\app\{#MyAppIcoName}"; \
                  Filename: "{app}\runtime\jre\bin\{#MyAppExeName}"; \
                  Parameters: " -jar {#MyJarName}"; \
                  WorkingDir: "{app}\app\"; \
                  Tasks: desktopicon            
          Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; \
                  IconFilename: "{app}\app\{#MyAppIcoName}"; \
                  Filename: "{app}\runtime\jre\bin\{#MyAppExeName}"; \
                  Parameters: " -jar {#MyJarName}"; \
                  WorkingDir: "{app}\app\"; \
                  Tasks: quicklaunchicon
        #else
          ; set up icons without bundled JRE
          Name: "{commonprograms}\{#MyAppName}"; \
                  IconFilename: "{app}\app\{#MyAppIcoName}"; \
                  Filename: "{app}\app\{#MyJarName}"; \
                  WorkingDir: "{app}\app\"
          Name: "{commondesktop}\{#MyAppName}"; \
                  IconFilename: "{app}\app\{#MyAppIcoName}"; \
                  Filename: "{app}\app\{#MyJarName}"; \
                  WorkingDir: "{app}\app\"; \
                  Tasks: desktopicon            
          Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; \
                  IconFilename: "{app}\app\{#MyAppIcoName}"; \
                  Filename: "{app}\app\{#MyJarName}"; \
                  WorkingDir: "{app}\app\"; \
                  Tasks: quicklaunchicon 
        #endif

        [Run]
        #if MyJREPath != ""
          ; run app with bundled JRE
          Filename: "{app}\runtime\jre\bin\{#MyAppExeName}"; Parameters: " -jar {#MyJarName}"; \
                  WorkingDir: "{app}\app\"; \
                  Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; \
                  Flags: postinstall skipifsilent          
        #else
          ; run app without bundled JRE
          Filename: "{app}\app\{#MyJarName}"; \
                  WorkingDir: "{app}\app\"; \
                  Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; \
                  Flags: shellexec postinstall skipifsilent          
        #endif 

希望这可以帮助你。

很棒的帮助。能够帮我将JRE与应用程序一起打包在Inno Setup 6中。 - Kwesi Aryee

3
JDK 7 Update 6及以上版本附带的Java打包程序是将JRE与您的代码一起嵌入本机可执行文件的官方方式一些Maven插件似乎可以打包和生成主要平台的本机可执行文件。
从JDK11开始,需要根据java-packager-with-jdk11下载Java打包程序,该程序演示了使用Gradle进行打包。
另一种方法可能是构建一个GraalVM本地映像,并找到使用反射的库的替代方案,因为反射不被支持。

不建议使用GraalVM,因为目前它并不完全支持Swing和AWT框架等。还有很多工作要做。 - gumuruh

2

我从未使用过Launch4J产品,祝你成功地配置它。

看起来你可以去Sourceforge的讨论论坛寻找其他提示 这里

其他建议:

我见过的IBM(Websphere)和Oracle的大多数产品只是在安装目录下提取一个JRE,并配置启动批处理命令以使用已安装的JRE。实际上,JRE和您的jar文件将在一次安装中安装。

安装exe通常会检查是否已经安装,并在发现已经存在时跳过该步骤。这对于仅升级jar文件非常有用。

本地安装还解决了客户安装其自己的可能不兼容或包含错误的JRE的问题。这样,您就可以处理已知的JRE版本。

如果您的应用程序没有图形组件,则选择excelsior路线是可以的(已经有一段时间,此限制可能已更改)。还有其他限制,但您最好只需使用单个可执行安装程序分发JRE及代码。


你似乎从我们产品的初期就开始了解它!事实上,Excelsior JET 早在 2005 年就获得了首个 Java 兼容性认证,因此自那时起就完全支持 Swing/AWT。它也可以很好地处理 Eclipse RCP,JavaFX 2 有点棘手但也能工作。您可以从图库中下载本地编译的 Eclipse 4.2 Classic 和 JavaFX 2 Ensmeble 演示:http://www.excelsior-usa.com/jetgallery.html 声明:我是 Excelsior 的员工。 - Dmitry Leskov

1
很容易将jre捆绑到launch4j中。
只需将jre复制到相同的输出文件夹中。
在“bundle jre environment”文本框中,只需给出jre文件夹本身。
在环境变量文本框中(位于同一页下方),给出直到bin为止。
然后创建exe。即使机器上没有jre,它也可以正常工作。
谢谢。

1
这假定您正在使用其他方法在目标计算机上安装JRE,而该方法与Launch4j构建的.exe文件并存。 - simpleuser

0

Execelsior已经死了... - gumuruh

-3

有没有办法在没有JRE的情况下运行可执行的jar文件?我曾经认为这是不可能的。另外,使用Web Start时,应用程序是否必须在线才能工作? - MagicGuy52
不,可执行的JAR需要一个JRE。Webstart不一定要在线,您可以将其指向本地位置。唯一的限制是您需要使用浏览器打开它,并在JNLP文件中包含<offline-enabled>节点。这里有一个关于如何做到这一点的好问题:local-alternative-to-jnlp-file - Matt Klooster

-3

有几个原因导致launch4j无法顺利运行。其中一些原因是:

1)用户未以管理员身份运行应用程序

2)用户未正确设置图标图像。必须严格使用.ico格式。


是的,我使用了 .jpg 图标,这导致了上述的 JRE 错误。 - Ebraheem Alrabeea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接