在Windows 7上启动Java应用程序的最佳方法是什么?

37

需求

我希望在Windows 7上发布一个Java GUI应用程序。该应用程序使用Swing工具包,不需要任何本地代码。该应用程序使用NSIS安装程序进行安装。我希望尽可能好地将此应用程序集成到Windows 7中。这意味着:

  • 当应用程序正在运行时,必须能够将应用程序固定到任务栏。
  • 必须能够将数据文件与应用程序关联,以便Windows使用我的应用程序打开这些文件。
  • 必须自动适配32位Java Runtime和64位Java Runtime。因此,当用户卸载32位Java并安装64位Java(或反之亦然)时,我的应用程序仍然必须正常工作。
  • 必须支持Windows的大字体设置。我真的不了解这个功能。我只知道有些应用程序完全忽略它,而其他应用程序(如Google Chrome)是像素缩放的(看起来非常丑陋),而其他应用程序则通过使用更大的字体来支持它(这就是我想要的,通常它可以正常工作。只有下面提到的WinRun4J解决方案不能与其一起使用)。

测试过的解决方案

WinRun4J

WinRun4j是一个EXE文件,用于启动Java应用程序。因为该应用程序不会派生出一个新的Java进程,所以Windows认为EXE文件就是该应用程序。因此任务栏没有问题。文件关联也可以工作,因为文件可以简单地与EXE文件相关联。

问题:

  • 不支持大字体。应用程序窗口是像素缩放的(像Google Chrome一样)。
  • 必须使用两个不同的EXE文件,具体取决于安装的JRE。因此,当64位JRE被安装时,必须使用64位EXE文件来启动应用程序。当32位JRE被安装时,则必须使用另一个EXE文件。这并不用户友好,因为用户不理解为什么在64位操作系统上只安装了32位JRE时,必须使用32位EXE。

Launch4J

Launch4J创建一个32位的EXE文件,启动外部Java进程来启动Java应用程序。因此,与WinRun4J不同,它也可以启动64位Java。

问题:

  • 无法将应用程序固定到任务栏。
  • 如果headerType="gui",则System.out.println不会打印到控制台,无论应用程序是否从控制台启动。

JAR

在Windows上,您只需双击JAR文件即可启动应用程序。安装的JRE并不重要,它可以简单地工作。但是...

问题:

  • 无法将应用程序固定到任务栏。
  • 无法在开始菜单中创建快捷方式。
  • 无法将文件与JAR文件关联。

BAT/CMD

可以使用类似于这样的简单批处理文件来启动应用程序:

@echo off
start c:\windows\system32\javaw.exe -jar "c:\program files\myapp\myapp.jar" %1

可以创建一个快捷方式来为这个批处理文件设置自定义图标。
问题:
  • 应用程序启动时会弹出一个DOS窗口。
  • 批处理文件不知道javaw.exe的位置。根据安装的Java版本(32位还是64位),它可能位于c:\windows\syswow64,而Windows不会自动从批处理文件重定向此调用。使用JAVA_HOME环境变量也不可行,因为Java不会自动设置它。
  • 当将文件与批处理文件关联时,无法设置自定义图标。
  • 任务栏支持无法正常工作。当手动启动批处理文件时,可以将应用程序固定到任务栏,但是双击关联的文件时却不起作用。

快捷方式

可以只创建一个快捷方式来启动应用程序,而不是使用批处理文件。它链接到此命令:c:\windows\system32\javaw.exe -jar "c:\program files\myapp\myapp.jar"。如果安装了32位Java JRE,则Windows会自动将此调用重定向到SysWOW64目录。

问题:
  • 由于Windows仅接受EXE / COM / PIF / BAT / CMD文件作为关联目标,因此无法将文件与其关联。LNK文件不起作用。

问题

是否有另一种解决方案满足上述所有要求?或者有没有什么诀窍来解决上述解决方案中的问题?

解决方案

使用Launch4j解决任务栏固定问题似乎是最佳解决方案。 Launch4j可以轻松集成到Maven项目中(使用thisthis插件),配置非常容易,并且除了任务栏固定之外,一切都可以直接使用。对于任务栏固定,Java应用程序必须设置appModelUserId,如this question中的答案所述。

此外,Java应用程序必须由一个安装程序安装,该安装程序至少必须安装一个指向EXE文件的快捷方式。该快捷方式还必须包含appModelUserId。使用NSIS,可以通过WinShell插件和以下配置来完成:

CreateShortCut "$SMPROGRAMS\MyApp.lnk" \
    "$INSTDIR\myapp.exe" "" "$INSTDIR\myapp.exe" 0 SW_SHOWNORMAL
WinShell::SetLnkAUMI "$SMPrograms\MyApp.lnk" "MyAppModelUserId"

由于某种未知原因,这个快捷方式只需要存在即可。您不必使用它。您可以双击EXE文件,任务栏固定仍然有效。您甚至可以在应用程序文件夹的某个子文件夹中创建快捷方式。当EXE文件的最后一个快捷方式被删除时,任务栏固定将停止工作。


1
根据安装的JRE,必须使用两个不同的EXE文件。这对用户来说真的很糟糕吗?几乎所有为x86和x64系统分发的软件都会强制用户决定要下载/安装/启动什么。我知道_Sysinternals ProcessExplorer_可以从一个exe在两个平台上运行,但他们只是将x64版本打包到x86中。此外,请查看_Launch4j_,也许它符合您的要求。 - lxbndr
1
@Mersenne:当这个决定取决于操作系统时,这不是问题。但在这种情况下,它取决于安装的JRE,这就是问题所在。用户下载64位应用程序版本,因为他们有64位Windows。然后他们抱怨应用程序无法工作,因为他们的Windows是由某些硬件供应商预装了32位Java。即使他们选择32位应用程序(或者安装程序自动做出此决定),当用户将32位JRE替换为64位JRE时,应用程序仍会崩溃。 - kayahr
是的,这确实是个问题 :( 我们可以把JRE看作是我们应用程序所需的一堆库。不兼容的库->应用程序无法运行。但对于用户来说,这并不是很清楚。 - lxbndr
5个回答

7
尝试使用Launch4j(http://launch4j.sourceforge.net/),它是一个简单的jar到exe封装器(实际上,封装jar是可选的)。它应该可以解决您的图标和任务栏要求。它还能够定位已安装的JRE(一些可配置规则)。我不太明白字体问题,Swing应该根据Windows设置自动使用字体,除非您在JRE选项或代码中覆盖了它。

1
我刚试了Launch4J。无法将应用程序固定到任务栏。无论是否包装JAR文件都没有关系。 - kayahr
第一个选项卡上有一个“自定义进程名称和XP样式清单”的选项,我认为那应该可以解决问题。 - Durandal
这篇博客文章声称它取决于.EXE文件的名称,我们无法尝试此方法,因为我们这里没有Win7:http://www.west-wind.com/weblog/posts/2009/Oct/08/Application-that-wont-Pin-to-Taskbar-in-Windows-7 - Durandal
我非常确定我的应用程序名称并不是一个保留名称。但我尝试将其重命名为一些随机的wkjbskdfjbnwer.exe,但没有帮助 :-) - kayahr
如果我理解正确,这里的解决方案更多地是偶然而非设计。Windows任务栏基于AppUserModelID值(可以在进程或窗口HWND实例上设置)来管理其元素。当没有显式值时,似乎使用了一些启发式方法:就好像根据安装的快捷方式猜测一样。快捷方式并不是真正必要的。对于包装的exe场景,调用setCurrentProcessExplicitAppUserModelID函数(来自Shell32.dll)将使任务栏图标可固定。 - Rekin
显示剩余3条评论

6

Java Web Start - 如今我不会考虑使用其他方式来分发应用程序。

用户需要至少拥有J2SE 1.4; 如果您的应用程序需要更新的版本,Web Start将自动下载适当的JRE。

请参阅JNLP参考文档,了解桌面集成标签(shortcutoffline-allowed)以及文件关联标签(association)。这些仅在WS 1.5中受支持。


你能提供一些像这样分发的好的应用程序链接吗?这样我就可以轻松地检查它的感觉了。如果用户还没有安装Java,会发生什么?安装程序可以在需要时自动下载和安装JRE,但WebStart如何工作呢? - kayahr
1
@kayahr Java教程中充满了Java Web Start的示例,例如这里:http://docs.oracle.com/javase/tutorial/ui/overview/demo.html - assylias
但是关于需求呢:是否可以将Web Start应用程序固定到任务栏上?您能否将文件扩展名与应用程序关联,以便通过双击数据文件启动应用程序?我认为不行。但也许我错了? - kayahr
@kayahr:支持文件关联,请参见我的编辑。恐怕我不知道它被固定时的行为如何(快速搜索表明可能会有问题)。我不在Windows 7上-为什么不尝试使用其中一个示例应用程序? - Dmitri
可以将WebStart应用程序固定到任务栏。只需告诉Windows如何启动您的应用程序即可。在Windows中,“java”和“javaw”可执行文件被配置为“主机”进程,因此需要一些应用程序协作。最简单的方法是使用某个exe包装器(启动器)来托管JVM:调用setCurrentProcessExplicitAppUserModelID即可。但是,如果不存在包装进程,则可以在Window实例上设置所需的选项(AppUserModelID和RelaunchCommand)。使用J7Goodies库非常容易。JNI / JNA也可以使用。 - Rekin
显示剩余13条评论

2

托盘不在我的需求列表中。我以前使用过它,它可以工作(除了图标的一些透明度问题)。这与Java应用程序的启动方式无关。它总是以相同的方式工作。 - kayahr
当你谈到任务栏的固定问题时,我误以为你实际上是在提到系统托盘...(我不是Windows 7用户...: )。肯定...抱歉。 - Yanflea
我在问题文本中将“Windows”更改为“Windows 7”,以使其更清晰。在其他版本的Windows上,“固定”不是一个问题,因为它根本不受支持。而且其他要求在所有Windows版本上都是相同的。 - kayahr

1

我总体上对WinRun4J的使用效果很好,但我并没有在字体方面做过太多尝试,所以我承认我不确定您描述的问题原因。

然而,从您的描述来看,似乎您对Java本地启动器有非常具体的要求。为什么不自己编写一个呢?你可以从类似WinRun4J这样的东西开始(它是开源的,根据Eclipse CPL许可),并将其修改为适合你的需求。

或者,您可以查看其他程序使用的本地启动器。 Eclipse和NetBeans启动器都似乎工作得非常好,而且两者都是开源的。 你也可能很容易适应其中之一。


我在Windows上尝试了Eclipse和Netbeans。结果是:它们都存在我想解决的同一个问题:无法将其固定到任务栏。右键单击图标只能显示“关闭应用程序”,没有固定选项。手动将启动器图标拖放到任务栏可以实现固定,但是当点击这些启动器后,任务栏中会出现第二个图标。 - kayahr
这是因为进程没有设置AppUserModelID。 - Rekin

1

另外,还要注意一下新功能,可以将您的应用程序放在工具栏/系统托盘中:

Oracle有一个tutorial,介绍如何使用系统托盘。

这与Java SE 6有关...让我也想知道新的Java 7中可能还有哪些好东西?


使用托盘并不是良好集成到Windows的要求。托盘应仅用于通知,不幸的是,许多应用程序滥用它以实现其他目的。我的应用程序不需要通知,因此我不需要托盘。但是当我需要它时,使用它没有问题,与我启动应用程序的方式无关。 - kayahr

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