Дополняет ранее опубликованную статью об уменьшении размера дистрибутива, делая акцент не на модульности, а на особенностях создания дистрибутива для разных операционных систем.
Перечисляются произошедшие с Java 9 изменения. Описывается последовательность шагов, выполняемых скриптом сборки, с указанием мест, где возможно изменение поведения и настройка. Приводится история со счастливым финалом преодоления особенностей и ошибок, появившихся в Java 9.
Пролог
Настольные (desktop) приложения, написанные на языке програмирования Java, по-прежнему имеют право на существование. Самым ярким примером является IntelliJ IDEA, дистрибутивы для установки которой существуют для разных операционных систем.
В JDK включена утилита командной строки Java Packager, служащая для компиляции, создания цифровой подписи и сборки дистрибутивов Java-приложений. Утилита впервые появилась в JDK 7 Update 6. Кроме использования в командной строке её функции доступны в виде задач (tasks) для Ant. В документации они именуются JavaFX Ant Tasks.
При написании статьи были использованы:
- операционные системы Windows 10, macOS High Sierra 10.13, Ubuntu 16.04.3 LTS;
- JDK 9 и JDK 10 Early-Access Builds для всех трёх операционных систем;
- Apache Maven 3.5.0;
- Inno Setup 5.5.9;
- IDE с поддержкой Java 9 и Java 10 (например, IntelliJ IDEA 2017.3.2 или позднее).
Проект может быть найден на GitHub. Компиляция и сборка дистрибутива осуществляется при помощи Maven. Проект примера включает три части (модуля в терминологии Maven):
- multiplatform-distribution-client с кодом приложения;
- multiplatform-distribution-distrib со вспомогательными файлами дистрибутива;
- multiplatform-distribution-resources с ресурсами для инсталляторов.
Сборка дистрибутива
В таблице перечислены в порядке выполнения этапы формирования дистрибутивов. Специально выделены жирным те этапы, на которых может возникнуть необходимость или желание изменить поведение, внешний вид или состав дистрибутивов.
№ п/п | Модуль Maven | Плагин Maven | Фаза жизненного цикла Maven | Этап |
---|---|---|---|---|
1 | multiplatform-distribution-resources | maven-resources-plugin | process-resources | Подстановка строковых значений в файлах .iss (для Windows) и .plist (для macOS) |
2 | multiplatform-distribution-client | maven-dependency-plugin | generate-sources | Формирование списка зависимостей для манифеста |
3 | build-helper-maven-plugin | generate-sources | Замена разделителя в списке зависимостей для манифеста | |
4 | maven-compiler-plugin | compile | Компиляция кода | |
5 | maven-jar-plugin | package | Создание файла .jar |
|
6 | maven-dependency-plugin | package | Копирование зависимостей для дистрибутива | |
7 | maven-resources-plugin | package | Копирование дополнительных файлов для дистрибутива | |
8 | maven-antrun-plugin | package |
|
|
9 | maven-assembly-plugin | package | Формирование файла дистрибутива .tar.gz для Linux (только при запуске на Linux) |
|
10 | multiplatform-distribution-distrib | maven-assembly-plugin | package |
|
Чтобы создать дистрибутивы в macOS и Linux, нужны только JDK и Maven. В операционной системе Windows предварительно необходимо установить Inno Setup или WiX Toolset. Далее подразумевается, что используется Inno Setup.
Запуск компиляции и сборки дистрибутива в Windows и macOS:
mvn clean package -P native-deploy
Запуск компиляции и сборки дистрибутива в Linux (дополнительно создаётся файл архива
tar.gz
):mvn clean package -P native-deploy,tar-gz
Файлы созданного дистрибутива с расширением
exe
, dmg
располагаются в каталоге multiplatform-distribution-client/target/deploy/native
, с расширением tar.gz
— в каталоге multiplatform-distribution-client/target
.Универсальный дистрибутив с расширением
zip
, пригодный для любой операционной системы и не содержащий в себе JRE, создаётся в каталоге multiplatform-distribution-distrib/target
.Особенности Java 9 и 10
Долгожданный выход Java 9 деструктивно повлиял на скрипт сборки дистрибутива, до этого успешно работавший в предыдущей версии Java.
Во-первых, задача <fx:deploy>, выполняющая формирование образа JRE и создание дистрибутива, немного изменила структуру используемых ею каталогов. Скрипт сборки был изменён, чтобы учесть это.
Во-вторых, при создании инсталляторов дистрибутивов перестали загружаться текстовые и графические ресурсы, см. JDK-8186683. Невозможность загрузки ресурсов из classpath при сборке дистрибутива в Java 9 компенсирована добавлением нового аргумента dropinResourcesRoot. В качестве значения аргумента рекомендуется указать путь к каталогу с ресурсами. В описании задачи в файле
pom.xml
это будет выглядеть так:В-третьих, из-за допущенных ошибок в реализации в Java 9 пропала возможность включать в дистрибутив подкаталоги с файлами, например, подкаталог
lib
с библиотеками-зависимостями программы. Ошибка проявлялась только в Windows и macOS. Преодоление этой проблемы превратилось в целую детективную историю и вынужденно растянулось на долгое время, отсрочив публикацию статьи. Хроника событий:
- Клонирован репозиторий OpenJFX и найдена ошибка.
- Обнаружен уже существующий JDK-8179033 с описанием тех же симптомов.
- По совету lany (спасибо ему большое) написаны письма раз и два в группу openjfx-dev, с предложением изменений, требуемых для исправления ошибки, и советом, как их правильность проверить.
- Переписка с исполнителями JDK-8179033 — благодарю Виктора Дроздова за доброжелательное отношение и терпение.
- Ошибка исправлена и исправление попало в очередную сборку предварительной версии Java 10 — jdk-10-ea+36.
- Сборка дистрибутива, запущенная из командной строки, стала выполняться успешно.
- При попытке в IntelliJ IDEA добавить jdk-10-ea+36 в список SDK — ошибка (в отличие от предыдущих сборок), создан IDEA-183920.
- Комментатором IDEA-183920 указана причина ошибки добавления JDK — исчезнование именно в этой сборке JDK утилиты javah, в том числе наличие которой требовалось для успешной идентификации.
- Выход IntelliJ IDEA 2017.3.2, в которой ошибка идентификации JDK 10 исправлена.
- Сборка дистрибутива стала возможна из среды разработки тоже.
Адаптация примера для собственного использования
- Переименовать модули Maven проекта, заменив префикс multiplatform-distribution в наименовании на что-то другое.
- Переименовать файлы
multiplatform-distribution.bat
иmultiplatform-distribution.sh
, находящиеся в модуле multiplatform-distribution-distrib. - Изменить в файлах
pom.xml
:
- имена переименованных модулей Maven;
- имена каталогов, соответствующих переименованным модулям Maven.
- Изменить в файлах
assembly.xml
:
- имена переименованных модулей Maven;
- упоминания изменённых имён файлов
multiplatform-distribution.bat
иmultiplatform-distribution.sh
.
- Изменить в файле корневого
pom.xml
значения свойств с именами <app.*>, содержащие:
- полное наименование приложения;
- краткое наименование приложения;
- год (-a) copyright;
- код приложения в именах файлах;
- пакет приложения по умолчанию;
- наименование класса для запуска приложения.
- Добавить в модуль multiplatform-distribution-client собственный код.
- Изменить содержимое файлов
license.txt
иreadme.txt
в модуле multiplatform-distribution-client. - Изменить содержимое графических файлов и их имена в модуле multiplatform-distribution-resources.
Выводы
- стандартными средствами JDK 9 и 10 можно построить дистрибутивы для различных операционных систем;
- кастомизация состава, поведения и вида дистрибутивов относительно проста;
- в Java 9 появились некоторые особенности, которые были учтены при написании данной статьи.
Недавно появился JEP 311: Java Packager API & CLI для создания нового API и CLI (интерфейса командной строки) для Java Packager. JEP в настоящее время отклонён, ранее изменения планировалось произвести в JDK 10 и JDK 11. При возобновлении активности данная статья может получить продолжение в ближайшем будущем.
На предстоящих 4 марта (JBreak 2018 в Новосибирске) и 6-7 апреля (JPoint 2018 в Москве) конференциях имеется возможность посетить доклады на близкие темы по Java 9 и будущим версиям Java:
- JDK 9, Mission Accomplished: What next for Java? (Simon Ritter)
- Migrating to Java 9 modules (Sander Mak)
- Refactoring your code to Java 9 modules (Rabea Gransberger)
- JavaFX on JDK 9 (Gerrit Grunwald)
Комментарии (8)
kovserg
28.12.2017 02:52А как создать desktop дистрибутив для 32bit windows?
dbelob Автор
28.12.2017 14:49Начиная с версии 9, Oracle Java только 64-битная. Для предыдущих версий (7 и 8) можно создать 32-битный дистрибутив.
Требуемые действия:
- Скачать и установить, например, 32-битную Java 8.
- Изменить требуемые переменные окружения (
JAVA_HOME
,Path
) операционной системы. - В файле
pom.xml
(главном) заменить значение переменной на<project.build.javaVersion>1.8</project.build.javaVersion>
. - В файле
pom.xml
(модуля multiplatform-distribution-client) заменить значение системного пути к файлуant-javafx.jar
на<systemPath>${java.home}/../lib/ant-javafx.jar</systemPath>
.
kovserg
28.12.2017 22:01+1Грусть, печаль владельцам 32bit десктопов или ну её нафиг java9+?
dbelob Автор
28.12.2017 22:53В предварительных сборках (Early-Access Builds) для Java 9 поддержка 32-битности ещё была, но в окончательном выпуске — уже нет. Достаточно подробное изложение истории в хронологическом порядке в ответе на Stack Overflow.
При наличии 32-разрядных операционных систем тогда уж пользоваться Java 8, при 64-разрядной — самой последней версией, какая есть.kovserg
29.12.2017 04:10Планируется переход на частый выпуск новых версий, oracle забивает на 32bit платформы. Sun WORE потихоньку становится Oracle whore (что бы всё работало нужно больше золота).
Кстати java 10 не будет будут 18.3, 18.9,… Adobe уже довела до совершенства flash. Чем Oracle хуже. Вобщем продолжаем наблюдения, но пака не поздно переходим обратно на C++.
ps: Несмотря на все улучшения и другие навороты все программы написанные на java досих пор пользуются славой как самые прожорливые и не поворотливые, имеющее внутри эпическое количество абстракций. При этом 64бит java как и раньше имеет 16 битые индексы на поля, константы и методы.
pps: Изображенный на картинке Дюк, кидающий windows, macos и linux как бы намекает будет вам еще java-coredbelob Автор
29.12.2017 12:34Кстати java 10 не будет будут 18.3, 18.9,…
Уже ранее успели передумать, следующая версия будет как раз Java 10: письмо Марка Рейнхольда, новость о том же в еженедельном дайджесте JUG.ru, упоминание об этом в недавнем обзоре на InfoWorld и т.д.
Предварительная версия именно JDK 10 упоминается и в данном хабрапосте.
Tishka17
Правильно ли я понял, что под линукс создание rpm/deb/etc. не рассматривалось? Без них не так интересно
dbelob Автор
При сборке дистрибутива под Linux сейчас создаются все возможные виды дистрибутивов при текущих значениях параметров (см.
nativeBundles="all"
у элемента<jfxdeploy>
в файлеpom.xml
для модуля multiplatform-distribution-client).Для задачи
<fx:deploy>
все возможные значения параметраnativeBundles
приведены в документации по указанной ссылке. Среди форматов есть иdeb
, иrpm
. Проall
сказано, что: