
Привет, Хабр.
Недавно в нашей компании возникла потребность в небольшой утилите для Windows пользователей.
Вся логика была уже реализована на Java библиотеках, так что оставалось только UI оболочка. Для этого была выбрана JavaFX. Приложение получилось красивое и удобное. На следующем шаге мы решили сделать исполняемое приложение из нашего JavaFX application, и для этого мы использовали инструмент jpackage.
Давайте рассмотрим, как это работает. Чтобы создать исполняемый файл для проекта JavaFX, вы можете воспользоваться несколькими подходами. Один из самых распространенных способов — использование инструмента jpackage, который входит в состав JDK начиная с версии 14. Этот инструмент позволяет упаковать ваш JavaFX проект в исполняемый файл для различных операционных систем.
Сборка исполняемого файла через gradle
Создание исполняемого файла происходит через специальный плагин: 'org.beryx.jlink' . Для Java17 подходит версия 2.24.1 (а для Java21 версия 3.1.1).
Документация здесь
Процесс делится на несколько этапов:
Сборка самого проекта в jar файл.
Подготовка образа Java.
Создание исполняемого файла для конкретной операционной системы.
Создание дистрибутива — установочного файла для конкретной операционной системы.
Мы рассмотрим вариант для ОС Windows.
Для этого шага нам понадобится дополнительно установить WiX Toolset.
Его последнюю версию можно скачать тут и добавить в переменную среды PATH.
Шаги:
У нас есть JavaFx приложение, которое собирается и запускается.
1. Подключить плагин в build.gradle
id 'org.beryx.jlink' version '2.24.1'
2. Добавить task в build.gradle
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'WinApplication'
}
jpackage() {
if (org.gradle.internal.os.OperatingSystem.current().windows) {
imageOptions += ['--icon', 'icon.ico']
}
imageOptions += ['--vendor', 'MyCompany'
]
installerOptions += [
'--vendor', 'MyCompany',
'--app-version', version
]
}
}
jlink
— создаст для нас образ java со всеми нашими зависимостями.
launcher {
name = 'WinApplication' - Здесь указывается наименование нашего приложения, будет соответственно 'WinApplication.exe'.
}
Jpackage
— отвечает за создание самого исполняемого файла и установочного файла.
imageOptions += ['--icon', 'icon.ico']
— определяет иконку для приложения, если не указывать эту опцию, то будет иконка по умолчанию.

'--vendor', 'MyCompany'
— если мы хотим указать производителя.
'--app-version', version
— определяет версию (важно не использовать при указании версии «SNAPSHOT» (например, “1.0.0-SNAPSHOT” — будет ошибка.)
3. Запускаем создание образа для инсталлятора
gradlew jpackageImage
получаем сам исполняемый файл.

По сути, WinApplication.exe уже можно запускать.

4. Запускаем создание дистрибутива
gradlew jpackage

Создались два файла для установки:WinApplication-1.0.0.exe и WinApplication-1.0.0.msi
Пример. build.gradle
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
id 'org.beryx.jlink' version '2.24.1'
}
group 'com.example'
version '1.0.0'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.8.1'
}
sourceCompatibility = '17'
targetCompatibility = '17'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'com.example.winapplication'
mainClass = 'com.example.winapplication.WinApplication'
}
javafx {
version = '17.0.1'
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'WinApplication'
}
jpackage() {
if (org.gradle.internal.os.OperatingSystem.current().windows) {
imageOptions += ['--icon', 'icon.ico']
}
imageOptions += ['--vendor', 'MyCompany'
]
installerOptions += [
'--vendor', 'MyCompany',
'--app-version', version
]
}
}
jlinkZip {
group = 'distribution'
}
Пример всего проекта можно посмотреть тут
P.S. Для Linux данный плагин работает без изменений.


linuxApplication — наше приложение
linuxapplication-1.0.7-1.x86_64.rpm и linuxapplication-1.0.7-1_amd64.deb — установочные пакеты.

Приложение запускается!