Статья рассказывает о построении дистрибутивов приложений для операционных систем Windows, macOS и Linux в случае использования Java 21 и 22.

Продолжает ранее опубликованную статью о создании дистрибутивов в предыдущих версиях Java, подробно описывая кардинальные изменения, произошедшие с того времени.

История вопроса


Инструменты, позволяющие выполнять компиляцию, сборку, создание цифровой подписи и дистрибутивов Java-приложений, впервые появились в JDK 7 Update 6. Первоначально они предназначались в первую очередь для JavaFX-приложений и были доступны в виде утилиты командной строки javafxpackager и в виде задач (tasks) для Ant. В официальной документации задачи для Ant имеют наименование JavaFX Ant Tasks.

В Java 8 утилита командной строки изменила наименование на Java Packager. JavaFX Ant Tasks сохранили своё название. Вошедший в Java 9 JEP 275: Modular Java Application Packaging был направлен на интеграцию модульности в Java Packager, в том числе для создания образа JRE, включающего только те модули, которые использует приложение. Предыдущая статья демонстрировала использование JavaFX Ant Tasks посредством их запуска из Maven с помощью плагина Maven AntRun Plugin.

Появившийся в 2017 году JEP 311: Java Packager API & CLI был направлен на создание нового API и CLI (интерфейса командной строки) для Java Packager. Изменения планировали произвести в JDK 10 и JDK 11, но данный JEP был отклонён и не вошёл ни в одну из последующих версий Java.

Попытка в 2018 году была возобновлена в рамках JEP 343: Packaging Tool (Incubator), результат работы впервые появился в JDK 14 в виде экспериментальной версии (т.н. incubator) утилиты командной строки jpackage. Продолжением стал созданный в 2020 году JEP 392: Packaging Tool и окончательная версия jpackage, вошедшая в JDK 16.

Существуют плагины для Maven и Gradle, являющиеся обёрткой над утилитой jpackage (например, этот, этот и этот), однако наиболее удобным и популярным на настоящий момент является гибридный плагин для Maven и Gradle JavaPackager, написанный Francisco Vargas Ruiz. Плагин JavaPackager никак не использует утилиту jpackage, выполняя все действия самостоятельно (или с помощью других Java-библиотек и утилит), содержит значительное количество коммитов и имеет много звёзд на GitHub.

Выполняемые плагином JavaPackager действия


Плагин JavaPackager выполняет следующую последовательность действий:

  1. Создаёт структуру каталогов дистрибутива.
  2. Добавляет в дистрибутив файл лицензии и прочие файлы ресурсов, если они были указаны.
  3. Создаёт подкаталог libs и копирует в него файлы зависимостей Java-приложения.
  4. Собирает для приложения исполняемый файл jar.
  5. Формирует образ JRE, включающий только те модули, которые использует приложение. Для определения списка используемых модулей Java применяется утилита jdeps, для формирования образа JRE — утилита jlink.
  6. Создаёт исполняемый файл, который будет использован на следующем шаге:
    • в Windows — файл формата exe, по умолчанию для этого используется инструмент Launch4j (можно использовать вместо него WinRun4J или Why);
    • в macOS — файл shell-скрипта на основе universalJavaApplicationStub, запускающего исполняемый файл jar, созданный на предыдущем шаге;
    • в Linux — файл shell-скрипта, являющегося обёрткой исполняемого файла jar, созданного на предыдущем шаге.
  7. Формирует файл инсталлятора, выполняющего действия по установке дистрибутива в операционной системе:
    • в Windows в виде файла exe (будет использован Inno Setup), файла msi и msm (их формирование выполняет WiX Toolset);
    • в macOS в виде файлов dmg (используется утилита hdiutil) и pkg (используется утилита pkgbuild);
    • в Linux в виде файлов deb (для его создания используется библиотека jdeb), rpm (создаётся с помощью библиотеки Redline), AppImage (создаётся с помощью утилиты appimagetool).
  8. Собирает архивы формата zip и tar.gz с дистрибутивом без инсталлятора.

Практически на всех шагах поведение может быть настроено и изменено в определённых пределах. Например, может быть оставлено формирование только нужных форматов файлов дистрибутивов.

Пример сборки дистрибутива


Репозиторий с кодом примера находится на GitHub. Для проверки запуска сборки дистрибутивов были использованы:


Компиляция и сборка дистрибутива осуществляется при помощи Maven. Проект примера включает две части (модуля в терминологии Maven):

  • multiplatform-distribution-client с кодом приложения;
  • multiplatform-distribution-distrib со вспомогательными файлами дистрибутива.

В таблице перечислены в порядке выполнения этапы формирования дистрибутивов. Специально выделены жирным те этапы, на которых может возникнуть необходимость или желание изменить поведение, внешний вид или состав дистрибутивов.
№ п/п Модуль Maven Плагин Maven Фаза жизненного цикла Maven Этап
1 multiplatform-distribution-client maven-dependency-plugin generate-sources Формирование списка зависимостей для манифеста
2 build-helper-maven-plugin generate-sources Замена разделителя в списке зависимостей для манифеста
3 maven-compiler-plugin compile Компиляция кода
4 maven-jar-plugin package Создание файла .jar
5 maven-resources-plugin package Копирование дополнительных файлов для дистрибутива
6 javapackager package
  1. Использование графических и конфигурационных файлов для сборки дистрибутива
  2. Создание образа JRE
  3. Формирование дистрибутива для конкретной операционной системы

7 copy-rename-maven-plugin package Переименование файлов дистрибутива
8 multiplatform-distribution-distrib maven-assembly-plugin package
  1. Подстановка строковых значений в файлах .bat (для Windows), .sh (для macOS и Linux) и лицензии
  2. Формирование универсального дистрибутива .zip (без JRE)


Чтобы создать дистрибутивы в macOS и Linux, нужны только JDK и Maven. В операционной системе Windows предварительно необходимо установить Inno Setup.

Запуск компиляции и сборки дистрибутивов:

mvn clean package -P native-deploy

Файлы созданного дистрибутива с расширением exe (для Windows), dmg (для macOS), с расширениями tar.gz, deb, rpm (для Linux) располагаются в каталоге multiplatform-distribution-client/target.

Универсальный дистрибутив с расширением zip, пригодный для любой операционной системы и не содержащий в себе JRE, создаётся в каталоге multiplatform-distribution-distrib/target.

Для получения только файла универсального дистрибутива с расширением zip:

mvn clean package

Адаптация примера для собственного использования


  1. Переименовать модули Maven проекта, заменив префикс multiplatform-distribution в наименовании на что-то другое.
  2. Переименовать файлы multiplatform-distribution.bat и multiplatform-distribution.sh, находящиеся в модуле multiplatform-distribution-distrib.
  3. Изменить в файлах pom.xml:
    • имена переименованных модулей Maven;
    • имена каталогов, соответствующих переименованным модулям Maven.
  4. Изменить в файле assembly.xml:
    • имена переименованных модулей Maven;
    • упоминания изменённых имён файлов multiplatform-distribution.bat и multiplatform-distribution.sh.
  5. Изменить в файле корневого pom.xml значения свойств с именами <app.*>, содержащие:
    • полное наименование приложения;
    • краткое наименование приложения;
    • год (-ы) copyright;
    • код приложения в именах файлах;
    • пакет приложения по умолчанию;
    • наименование класса для запуска приложения.
  6. Добавить в модуль multiplatform-distribution-client собственный код.
  7. Изменить содержимое файлов license.txt и readme.txt в модуле multiplatform-distribution-client.
  8. Изменить содержимое файлов и их имена в подкаталоге assets модуля multiplatform-distribution-client.

Как собираются дистрибутивы IntelliJ IDEA для разных операционных систем


Компания JetBrains поставляет дистрибутивы самой популярной среды для Java-разработки IntelliJ IDEA в виде файлов следующих форматов:

  • для Windows — файлов форматов exe и zip;
  • для macOS — файла формата dmg;
  • для Linux — файла формата tar.gz.

Каким образом выполняется сборка файлов дистрибутивов, можно узнать, изучив исходный код IntelliJ IDEA Community Edition из репозитория на GitHub. Для сборки дистрибутивов не используется ни утилита jpackage, ни какие-либо плагины. Для формирования файлов дистрибутивов предназначен скрипт installers.cmd, расположенный в корневом каталоге репозитория. Данный скрипт последовательно использует классы, начиная с общего OpenSourceCommunityInstallersBuildTarget и заканчивая специфичными для каждой из операционных систем WindowsDistributionBuilder, MacDistributionBuilder и LinuxDistributionBuilder. Cкрипт выполняет следующие действия:

  1. Создаёт структуру каталогов дистрибутива.
  2. Добавляет в дистрибутив необходимые файлы ресурсов.
  3. Создаёт подкаталог и копирует в него файлы зависимостей Java-приложения.
  4. Собирает для приложения файлы jar.
  5. Добавляет каталог с JetBrains Runtime.
  6. Формирует файл инсталлятора, выполняющего действия по установке дистрибутива в операционной системе:
    • в Windows в виде файла exe (используется NSIS, Nullsoft Scriptable Install System);
    • в macOS в виде файлов dmg (используется утилита hdiutil);
    • в Linux в виде файлов tar.gz (создаётся с помощью библиотеки Apache Commons Compress).
  7. Собирает архив формата zip, содержащий файлы для всех операционных систем, используя для его создания стандартные классы JDK из пакета java.util.zip. Данный архив имеет в имени суффикс .portable и не выкладывается на веб-сайт для скачивания.

Выводы


  1. Стандартным средством создания файлов дистрибутивов для различных операционных систем в JDK сейчас служит утилита jpackage.
  2. Наиболее удобным и популярным средством сборки с использованием Maven и Gradle является плагин JavaPackager.
  3. Самостоятельное создание собственного инструмента для сборки дистрибутивов подобно компании JetBrains возможно, но потребует много ресурсов для написания кода и его сопровождения.
  4. В настоящее время разумно выбрать JavaPackager при необходимости распространения Java-приложений с возможностью их установки пользователем в Windows, macOS и Linux.

9 октября 2024 года (онлайн) и 15-16 октября 2024 года (офлайн в Санкт-Петербурге и онлайн) состоится конференция для Java-разработчиков Joker 2024, на которую открыт приём заявок на доклады и можно купить билеты.

Комментарии (0)