PunchKwara doctors lament poor pay, illegal salary deductionsEl Comercio¿Meta favorece a Flávio Bolsonaro y perjudica a Lula? Las claves de la polémica electoral en BrasilRTP DesportoMotoGP: terminou a temporada para RazgatliogluESPNTransfer rumors, news: Premier League clubs eye Alexander-Arnold amid Real Madrid uncertaintyThe Jerusalem PostMandelblit says he approved questioning Netanyahu as suspect, defense challenges wordingDaily MaverickHegseth meets Netanyahu in unannounced visit to Israel, source saysInquirerMarcos vows reforms to boost investor confidence, stock marketCollider‘Sense and Sensibility’ Officially Posts One of the Weekend’s Best Per-Theater AveragesObservador DesportoMoçambique. Supostos terroristas abatidos por fuzileirosSky TG24I titoli di Sky TG24 del 20 ottobre, edizione delle 8
The Daily Newsstand · Free, Always
Tuesday, October 20, 2026

jpackage от А до Я: как правильно упаковать Java‑приложение в десктопный дистрибутив

Translate

Начну с небольшой предыстории. Я начинал свой путь в IT с базового курса «Разработка программного обеспечения» в одной из профильных академий. Этого фундамента хватило для уверенного старта, но реальные коммерческие задачи часто выходят за рамки учебных программ.

Одной из таких «болей» стала дистрибуция Java‑приложений конечному пользователю. Сколько раз мы слышали от клиентов: «А у меня не запускается, наверное, Java не та»? Чтобы раз и навсегда избавиться от необходимости писать в README фразу «сначала установите JRE», я решил глубоко погрузиться в тему нативной упаковки.

В этой статье я систематизировал весь свой опыт работы с jpackage: от создания портативных версий до сборки полноценных инсталляторов для Windows, Linux и macOS, а также разобрал подводные камни при работе с JavaFX и Spring Boot.

jpackage— это мощный инструмент, встроенный в JDK (начиная с версии 14, JEP 343/392), который предназначен для упаковки Java-приложений в нативные образы для конкретных платформ. Он автоматически создает нативный лаунчер (запускатор) и включает в себя урезанную версию JRE (созданную черезjlink`), чтобы пользователю не нужно было устанавливать Java.

Далее так как я не знал изначально что умеет jpackage я для себя выделил два приоритета:
1. Создание Portable (портативных) приложений
2. Создание установочных пакетов (Installers)
Далее я расскажу о каждом из приоритетов и не только чтобы у каждого получилось поделиться своим приложением на Java без последующих лишних вопросов.

ПРИОРИТЕТ 1: Создание Portable (портативных) приложений

Портативное приложение (app‑image) — это папка, которую можно скопировать на любой компьютер (флешку, другой ПК) и запустить без установки. Она содержит ваш код, нативный лаунчер и скрытую JRE.

  1. Для ОС Windows

  • Результат: Папка с .exe файлом и подпапкой runtime.

  • Команда:

jpackage --type app-image --name "MyApp" --input ./target --main-jar myapp.jar --main-class com.example.Main --dest ./dist
  • Как сделать по‑настоящему portable: Просто заархивируйте полученную папку в ZIP. Пользователь распаковывает её и запускает .exe.

  • Важно: Если вы хотите, чтобы приложение работало на старых версиях Windows (например, Win 7), убедитесь, что вы собираете его на JDK, скомпилированной для нужной архитектуры, и учитывайте зависимости C++ runtime (обычно jpackage подтягивает нужные DLL, но иногда требуется Visual C++ Redistributable).

<ol start=«2»>
<li>Для ОС Linux</li>
</ol>

  • Результат: Папка с исполняемым скриптом/бинарником и подпапкой runtime.

  • Команда:

jpackage --type app-image --name "MyApp" --input ./target --main-jar myapp.jar --main-class com.example.Main --dest ./dist
  • Ограничения «портативности» в Linux: В отличие от Windows, Linux‑портативность условна. Скомпилированная JRE будет зависеть от версии glibc (GNU C Library) и графических библиотек (X11/Wayland, GTK) той системы, где происходила сборка.

  • Решение:* Собирайте portable‑версию для Linux на самой старой целевой версии дистрибутива (например, на Debian 10 или Ubuntu 18.04), чтобы обеспечить обратную совместимость glibc.

ПРИОРИТЕТ 2: Создание установочных пакетов (Installers)

jpackage умеет создавать нативные инсталляторы. Внимание: для их создания на машине сборщика должны быть установлены сторонние утилиты.

  1. Windows (MSI и EXE)

  • Формат:** .msi (нативно через WiX Toolset).

  • Требования: Установлен WiX Toolset 3.0 или новее и добавлен в PATH.

  • Команда:

jpackage --type msi --name "MyApp" --app-version 1.0.0 --input ./target --main-jar myapp.jar --main-class com.example.Main --win-menu --win-dir-chooser --dest ./dist
  • Примечание: jpackage не создает .exe инсталляторы (вроде InnoSetup) напрямую. Он создает MSI. Если нужен EXE, MSI можно обернуть в EXE через WiX Burn Bundle или InnoSetup пост‑фактум.

<ol start=«2»>
<li>Linux (DEB и RPM) </li>
</ol>

  • Форматы: .deb (для Debian/Ubuntu), .rpm (для RHEL/Fedora).

  • Требования: Установлены dpkg-deb (для deb) и rpmbuild (для rpm).

  • Команда (для DEB):

jpackage --type deb --name "myapp" --app-version 1.0.0 --input ./target --main-jar myapp.jar --main-class com.example.Main --linux-shortcut --linux-menu-group "Utility" --dest ./dist

<ol start=«3»>
<li>macOS (DMG и PKG)</li>
</ol>

  • Форматы:** .dmg (образ диска), .pkg (инсталлятор).

  • Требования: Сборка должна происходить только на macOS.

  • Команда:

jpackage --type dmg --name "MyApp" --app-version 1.0.0 --input ./target --main-jar myapp.jar --main-class com.example.Main --mac-package-identifier com.example.myapp --dest ./dist

ПРИОРИТЕТ 3: Запуск разных типов Java‑приложений

Главное правило jpackage: он запускает то, что запускает стандартная java -jar, но через нативный лаунчер. Однако есть нюансы для разных UI.

  1. Консольные приложения (CLI)

  • Проблема: В Windows по умолчанию лаунчер jpackage скрывает консольное окно, так как считает приложение GUI‑ным.

  • Решение:** Используйте флаг --win-console.

  • Команда:

jpackage --type app-image --name "MyCLI" --input ./target --main-jar mycli.jar --main-class com.example.CLI --win-console --dest ./dist
  • Для Linux/macOS:* Консоль и так будет видна при запуске из терминала. Если нужен запуск по клику, создайте .sh скрипт‑обертку.

<ol start=«2»>
<li>Swing / AWT приложения</li>
</ol>

  • Особенности:** Работают «из коробки». Но в Windows могут быть проблемы с масштабированием (DPI) и рендерингом.

  • Решение: Передайте JVM‑аргументы для улучшения рендеринга.

  • Команда:

jpackage --type app-image --name "MySwingApp" --input ./target --main-jar myswing.jar --main-class com.example.SwingUI --java-options "-Dsun.java2d.d3d=true" --java-options "-Dsun.java2d.ddscale=true" --dest ./dist

<ol start=«3»>
<li>3. JavaFX приложения (Самый сложный случай!)</li>
</ol>

С версии JDK 11 JavaFX отделена от JDK. jpackage не умеет автоматически подтягивать JavaFX, если вы используете «fat jar» (JAR со всеми зависимостями внутри).

  • Вариант А (Модульное приложение — РЕКОМЕНДУЕТСЯ): Если ваше приложение модульное (есть module-info.java), jpackage сам всё поймет.

jpackage --type app-image --name "MyFXApp" --input ./target --main-jar myfx.jar --main-class com.example.FXApp --dest ./dist
  • Вариант Б (Немодульное приложение / Fat JAR): Вам нужно явно указать module-path и добавить модули JavaFX, иначе вы получите ошибку GraphicsDevice initialization failed.

jpackage --type app-image --name "MyFXApp" \
  --input ./target \
  --main-jar myfx.jar \
  --main-class com.example.FXApp \
  --module-path /path/to/javafx-sdk/lib \
  --add-modules javafx.controls,javafx.fxml \
  --dest ./dist

Лайфхак: Если не хотите возиться с --module-path, создайте класс‑пустышку, наследующий javafx.application.Application, и укажите его как --main-class.

<ol start=«4»>
<li>Spring Boot приложения (Ограничение!)</li>
</ol>

  • Проблема:** Spring Boot создает «fat jar» (JAR внутри JAR). jpackage НЕ ПОДДЕРЖИВАЕТ вложенные JAR‑файлы. Он не сможет найти ваш main-class.

  • Решение 1 (Правильное):** Используйте maven-shade-plugin или spring-boot-maven-plugin с конфигурацией layout=ZIP и PropertiesLauncher, чтобы распаковать зависимости.

  • Решение 2 (Обходное): Извлеките все зависимости из fat‑jar в папку lib перед запуском jpackage, и передайте все JAR‑ы в --input.

# Сначала распакуем Spring Boot fat jar
# Затем упакуем через jpackage, указав главный класс Spring Boot
jpackage --type app-image --name "MySpringApp" --input ./extracted-libs --main-jar my-spring-app.jar --main-class org.springframework.boot.loader.PropertiesLauncher --dest ./dist

ВСЁ, ЧТО МОЖНО И НЕЛЬЗЯ ДЕЛАТЬ С jpackage

ЧТО МОЖНО (Возможности)

  1. Бандлинг JRE:** Автоматически создает минимальную JRE (через jlink), уменьшая размер дистрибутива с ~300 МБ до ~30-50 МБ.

  2. Кастомизация JVM:** Передача любых аргументов виртуальной машине (--java-options), например, выделение памяти (-Xmx1024m), настройка кодировки (-Dfile.encoding=UTF-8).

  3. Иконки и ресурсы:** Назначение нативных иконок (.ico для Win, .icns для Mac, .png для Linux) через --icon.

  4. Использование готовой JRE: Если вы заранее собрали идеальную JRE через jlink, вы можете скормить её jpackage через флаг --runtime-image, чтобы он вообще не трогал модули.

  5. Добавление файлов: Копирование конфигов, README, баз данных в папку приложения через --resource-dir или --file-associations.

  6. Ассоциация файлов:** Привязка расширений файлов к вашему приложению (чтобы双击 по файлу .myext открывал его в вашей программе) через --file-associations.

  7. Подпись кода (Code Signing): jpackage позволяет подписывать приложение.

    Windows: Через --win-upgrade-uuid и пост‑обработку signtool.

    macOS: Через --mac-sign, --mac-signing-key-user-name, --mac-signing-keychain.

ЧТО НЕЛЬЗЯ (Ограничения)

  1. Создание ОДНОГО файла (.exe /.appimage):** jpackage никогда не создает один исполняемый файл. Он всегда создает папку (для app-image) или архив/инсталлятор, внутри которого лежит папка с JRE. Сделать «портативный exe на 50 МБ» штатными средствами нельзя (нужны сторонние упаковщики вроде Enigma Virtual Box, но они ломают JRE).

  2. Компиляция кода:** jpackage не компилирует .java в .class. Ему нужны готовые .jar или .class файлы.

  3. Кросс‑компиляция:** Вы не можете собрать .msi или .dmg на Linux. Вы не можете собрать .deb на Windows. Сборка инсталляторов возможна только на той ОС, для которой она предназначена. (Исключение: app-image для Linux можно собрать на Windows, но он не будет работать без WSL/Cygwin, так что на практике собирайте на целевой ОС).

  4. Нативное шифрование кода: jpackage не защищает ваш код от декомпиляции. Ваш .jar внутри пакета лежит в открытом виде. Для защиты используйте обфускаторы (ProGuard, Zelix KlassMaster) до упаковки.

  5. Поддержка Nested JARs:** Как указано выше, Spring Boot fat‑jar «из коробки» не поддерживается.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.