如何为Java程序创建MSI Windows安装程序?

7
我希望创建一个Microsoft Installer文件,用于Java程序。由于法律原因,我不能使用Oracle Java和/或JavaFX,因此不能使用Netbeans或任何Maven插件来完成此操作,而且两者似乎都使用Oracle本机部署+JavaSE 1.8。 我的当前档案包括:
- Java运行环境(OpenJDK 1.7 JRE) - 一个脚本(.bat) - 一个fat JAR - 一个图标文件 - 几个文本文件
我不想使用系统的JRE,这就是为什么我提供另一个JRE的原因。脚本只是调用带有一些参数的JRE。图标文件以.ico格式存在。fat JAR是包含所有必要的Java类、本地库和资源(包括第三方库)的JAR。
我希望允许最终用户安装、运行和卸载我的程序。我想提供一个开始菜单中的快捷方式来运行它,另一个用于卸载它。这似乎在这里有解释。我是否需要使用其他东西来创建卸载程序的快捷方式?
我已经查看了Wix Toolset几个星期。我知道我必须编写一个wxs文件与"candle.exe"一起使用,它会创建一个wixobj文件,我必须使用此文件运行"light.exe",然后我会得到一个MSI文件。
我知道如何添加一个文件,这里有解释,但我不知道如何添加包含JRE的整个目录,而不是逐个列出每个文件。如何在wxs文件中完成?
如何选择一些唯一的GUID?

是否已经有一个更简单的工具可以用来从fat JAR制作MSI文件?在尝试使用Apache POI在GNU Linux下进行编程之前,我更喜欢先了解如何在Windows命令行中构建此类文件。

编辑:这是我的第一个wxs文件:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="*" Name="Truly Unusual Experience of Revolution" Language="1033" Version="0.0.0.0" Manufacturer="Julien Gouesse" UpgradeCode="00000000-0000-0000-0000-000000000000">
    <!-- Installer's Icon in Add/Remove Programs -->
 <Icon Id="icon.ico" SourceFile="tuerLogo.ico"/>
    <Property Id="ARPPRODUCTICON" Value="icon.ico" />
 <!-- Installer's version = 200 because the 64-bit support is required -->
    <Package InstallerVersion="200" InstallPrivileges="elevated" InstallScope="perMachine" Compressed="yes" Platform="x64" />
    <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
    <MajorUpgrade AllowDowngrades="yes" IgnoreRemoveFailure="yes" Schedule="afterInstallInitialize" />
    <Condition Message="This application is only supported on Windows XP, Windows Vista, Windows Server 2008, or higher.">
      <![CDATA[Installed OR (VersionNT >= 501)]]>
    </Condition>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="APPLICATIONROOTDIRECTORY" Name="Truly Unusual Experience of Revolution">
    <Component Id="tuer.bat" Guid="00000000-0000-0000-0000-000000000000">
            <File Id="tuer.bat" Source="tuer.bat" KeyPath="yes"/>
    </Component>
    <Component Id="tuer.jar" Guid="00000000-0000-0000-0000-000000000000">
            <File Id="tuer.jar" Source="tuer.jar" KeyPath="yes"/>
    </Component>
    <Component Id="LICENSE.txt" Guid="00000000-0000-0000-0000-000000000000">
            <File Id="LICENSE.txt" Source="LICENSE.txt" KeyPath="yes"/>
    </Component>
    <Component Id="NOTICE.txt" Guid="00000000-0000-0000-0000-000000000000">
            <File Id="NOTICE.txt" Source="NOTICE.txt" KeyPath="yes"/>
    </Component>
    <Component Id="README.txt" Guid="00000000-0000-0000-0000-000000000000">
            <File Id="README.txt" Source="README.txt" KeyPath="yes"/>
    </Component>
  </Directory>
      </Directory>
   <Directory Id="ProgramMenuFolder">
        <Directory Id="ApplicationProgramsFolder" Name="Truly Unusual Experience of Revolution"/>
      </Directory>
 </Directory>
 <!-- Shortcut in the Start Menu -->
 <DirectoryRef Id="ApplicationProgramsFolder">
      <Component Id="ApplicationShortcut" Guid="00000000-0000-0000-0000-000000000000">
        <Shortcut Id="ApplicationStartMenuShortcut" 
                  Name="Truly Unusual Experience of Revolution" 
                  Description="First person shooter"
                  Target="[#tuer.bat]"
                  WorkingDirectory="APPLICATIONROOTDIRECTORY"
         Icon="icon.ico" />
          <RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
          <RegistryValue Root="HKCU" Key="Software\Microsoft\TrulyUnusualExperienceofRevolution" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
      </Component>
    </DirectoryRef>
    <Feature Id="TrulyUnusualExperienceofRevolution" Title="Truly Unusual Experience of Revolution" Level="1">
   <ComponentRef Id="tuer.bat" />
   <ComponentRef Id="tuer.jar" />
   <ComponentRef Id="LICENSE.txt" />
   <ComponentRef Id="NOTICE.txt" />
   <ComponentRef Id="README.txt" />
   <ComponentRef Id="ApplicationShortcut" />
 </Feature>
  </Product>
</Wix>

编辑2:这个 文件是在JRE目录上运行“heat”命令得到的。

注意: 我不回答自己的问题,但当我发现使用NSIS(Nullsoft Scriptable Install System)构建安装程序会更容易时,我停止了调查,因为已经有一个Ant任务和一些软件包适用于多个GNU Linux发行版(包括Mageia, Fedora, ...),以使其正常工作。您可以找到一个名为Java Launcher的脚本来寻找您的软件和操作系统中的JRE(即使我建议您将OpenJDK JRE捆绑在您的软件中,以确保它将继续工作,尽管更新或操作系统中没有JRE),另一个带有自动JRE安装的脚本一个基于Java的软件的nsi脚本的简单示例

顺便提一下,我现在使用自己的工具(它在底层使用Redline RPM),它完全文档化、开源(根据GPL),并且适用于RPM、DEB、APP和EXE(通过NSIS),它被称为Java Native Deployment Toolkit


1
请查看 "heat.exe" 以从源目录树创建组件。GUID通常可以由 "candle" 生成,也就是说,可以从源中省略。 - Tom Blodget
一些管理员可能会拒绝您的JRE,并坚持要负责维护自己的JRE以便能够应用安全更新。您可以将您的JRE作为可选功能,以使他们能够这样做。 - Tom Blodget
你说得对,一些管理员要求承担JRE的责任。私有JRE不是系统范围内的,我可以“最小化”它。我可以从中删除大部分对我来说无用(在这个特定项目中)的部分,如Java插件、AWT、Swing、JavaFX等。我不想支持多个JRE,我知道OpenJDK的一些限制。在我看来,苹果JVM有时候是一场噩梦。一个更小的JRE,没有最麻烦的部分,比未改变的Oracle Java JRE更安全。只有当没有JRE可用时,安装OpenJDK可能会有些棘手,但是可行的。 - gouessej
@TomBlodget 热度目录 "my_dir" -模板:产品 -ag -输出 product.wxs 似乎是我想要的。 - gouessej
1
如果无法基于路径生成一致的GUID,则candle会报错。请忽略整个属性。 - Tom Blodget
显示剩余3条评论
4个回答

6

升级至Java 14+,并使用内置的jpackage工具(它是Jave 8/9中'jpackager' 的后代)。像大多数工具一样,它会为你所在的系统生成软件包:

  1. Linux: deb 和 rpm
  2. macOS: pkg 和 dmg
  3. Windows: msi 和 exe

它使用jdeps和jlink来构建最小化的JRE,并将其包含在安装程序中,无需单独下载Java。此外,它随每个JDK下载免费提供。感谢Kevin Rushforth和 JEP343 团队!阅读开发日志,请访问https://bugs.openjdk.java.net/browse/JDK-8200758,或执行jpackage --help命令。请注意,截至Java14,它仍然处于“孵化”阶段,因此某些功能可能会更改。


这是一个向好的方向迈出的一步,但是jpackage仍然无法为Windows下的GNU Linux生成软件包,在GNU Linux下生成Windows可执行文件,在GNU Linux下生成OS X软件包等等,与我的自有工具不同。 - gouessej
1
gouessej 但是,您必须为每个平台放置不同的依赖于平台的JRE,因此您是否需要为每个平台重新运行create-app-dir步骤?无论如何,如果它对您有效(显然是这样的 :-)),那就很好。 - idarwin
是的,这就是我所做的,我使用AdoptOpenJDK二进制构建,它非常好用。支持OS X确实是一场噩梦,因为有Gatekeeper和其他程序…我可以受益于JLink的交叉定位,创建一个最小的JRE并将其传递给JNDT: https://dev59.com/wFYN5IYBdhLWcg3wVm6n#47594270 你的建议很有价值。如果我有更多的空闲时间,我愿意做出贡献。 - gouessej

3

OpenJDK项目的javapackager适用于Java 8/9,具备将自定义JRE安装程序打包到MSI安装程序(使用WIX)中的能力。如果您不想使用Oracle Java提供的打包程序或者从OpenJDK源代码编译的程序,那么查看javapackager源代码也许可以帮助您创建自己的打包工具。

许可证似乎是您关心的问题 - 因此,如果您采用这种方法,您可以检查OpenJDK法律文件是否适用于您的情况。请注意,如果您使用OpenJDK,则Oracle BCL不适用。

我没有详细检查过javapackager源代码,但它可能依赖于Java 8的一些特性。由于您的目标是创建基于JRE 7的软件包,因此您可以使用Java 8运行时来执行打包程序,但将Java 7 JRE作为目标进行打包。如果您必须使用Java 7运行时来运行打包工具,并且打包器代码使用了Java 8的特性-您可以将其分叉并向后移植到Java 7(您需要一些非常严格的要求才能要求这样做-大多数人不会有这样的要求)。
我不建议上述方法作为完成任务的最理想方式-我只是提出了一些可能或可能对您有用的想法。

我的游戏是根据GPL第2版发布的。JavaSE和JavaFX的Oracle BCL(Oracle二进制代码许可协议)有点烦人,特别是当你想要删除一些无用的文件时:http://www.oracle.com/technetwork/java/javase/terms/license/index.html谢谢您的建议,这是值得一看的,因为源代码是可用的。 - gouessej
@gouessej 你有没有阅读关于可选文件的部分,网址为http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html? - swpalmer
是的,我试过了,它显示有几个文件可以合法删除,但它仍然不如使用OpenJDK灵活,OpenJDK多年来在我的日常使用中一直让我很满意 :) - gouessej

1
我运行一个名为IsWiX的开源项目,处理这种情况。您可以观看下面链接的视频来创建用于WPF .NET桌面应用程序的MSI文件。
对于Java应用程序,概念是相同的。您只需部署JRE的私有实例以及您的应用程序,并创建一个指向.BAT文件的快捷方式。您唯一要做的自定义操作就是创建一个指向ICO文件的图标元素,并在Shortcut元素上设置一个属性以指向该图标。在编译代码世界中,我们不必这样做,因为快捷方式将自动显示目标可执行文件中的默认图标资源。
有关该视频的简要介绍可以在此处找到: 使用IsWiX构建和部署Windows桌面应用程序 以及(无声)视频本身: 使用IsWiX构建和部署Windows桌面应用程序

我可以建议我的同事使用iswix,它似乎很有趣 :) 我会试一试,但是我必须理解它的源代码,以便在自己的工具中做同样的事情:https://svn.code.sf.net/p/tuer/code/pre_beta/jndt.xml 请问您能否确认我可以使用您的软件创建一个wxs文件?我需要了解“底层”是如何完成的。 - gouessej
1
Windows 8.1 显示了一个可怕的警告,因为该应用程序可能未经签名。我看到“我们”必须支付“通行费”,以便微软允许我们的最终用户无缝启动我们的软件 :s - gouessej
1
IsWiX仅是一组Visual Studio项目模板,提供脚手架和一个使用Linq to XML的.NET WinForms应用程序,为WiX XML提供可视化设计工具。生成的WiX XML不需要构建IsWiX。 - Christopher Painter
就我个人而言,我从不直接使用Candle和Light。我使用一个名为Votive的WiX功能,它提供了Visual Studio集成和MSBuild支持。最终我得到一个包含wix项目(.wixproj)和代码文件(.wxs)的解决方案(.sln)。我将其传递给MSBuild / Team Foundation Server,所有编译细节都会自动处理。最终,Candle和Light被调用,但我不必担心这些细节。 - Christopher Painter
我熟悉“一次编写,到处运行”的概念,但我不相信它。通常在Windows平台上用户体验较差。 - Christopher Painter
显示剩余13条评论

1

我刚偶然发现了这个问题,也许我的两分钱可以帮到你。

我同时使用了两个Maven插件:

1)launch4j-maven-plugin(com.akathist.maven.plugins.launch4j) 用于将jar打包成exe文件。它还允许指定最低Java版本。这样,您就不必随msi一起发布Java版本(需要定期更新),而只需将用户重定向到Java下载页面(轻量级解决方案)。Launch4J还具有其他功能,使您的Java应用程序更美观,例如启动屏幕或传递启动参数等。通过在pom.xml中设置某些属性,您可以构建非常自定义的安装程序。

2)wix-maven-plugin(org.bitbucket.joxley) 由于我们现在有了exe文件,我们可以创建一个非常漂亮的安装程序,其中包括桌面快捷方式和安装过程结束时的“立即启动”复选框。

这种组合并不是最容易实现的,但一旦建立起来,您就有无数选项来构建软件的不同版本(评估副本/专业版),以及定制软件(例如,安装程序外观不同,甚至可以附加不同的软件许可证)。使用在launch4J插件中设置的命令行参数,您可以创建一个以特定状态或特定配置启动的应用程序。我们已经在生产中使用这个解决方案几年了。

这是一个有趣的解决方案,但它有一个主要缺点:它只能在Windows下运行。 - gouessej
@gouessej 好的,问题是关于MSI Windows Installer的。你还想在哪里运行它? - haferblues
这个问题是关于创建一个Windows安装程序,但不一定是在Windows下进行,你运行安装程序的平台和创建安装程序的平台之间存在差异。我不想在Windows下构建我的软件。 - gouessej
@gouessej 你说得对。我只考虑了MSI安装程序文件。对于构建脚本,确实需要运行Windows的构建服务器。 - haferblues
对于其他读者而言,我想要避免的就是运行Windows的构建服务器。 - gouessej

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